(svn r1) Import of revision 975 of old (crashed) SVN

pull/155/head
truelight 20 years ago
commit efaeb275f7

@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
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
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
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 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
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
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
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
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
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
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
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
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
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
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
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
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
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
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
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
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 Library General
Public License instead of this License.

@ -0,0 +1,163 @@
CFILES = ai.c aircraft_cmd.c aircraft_gui.c airport_gui.c
bridge_gui.c clear_cmd.c command.c disaster_cmd.c
dock_gui.c dummy_land.c economy.c engine.c engine_gui.c
fileio.c gfx.c graph_gui.c industry_cmd.c industry_gui.c
intro_gui.c landscape.c main_gui.c minilzo.c misc.c
misc_cmd.c misc_gui.c music_gui.c namegen.c network.c
news_gui.c oldloader.c order_cmd.c order_gui.c pathfind.c
player_gui.c players.c rail_cmd.c rail_gui.c road_cmd.c
road_gui.c roadveh_cmd.c roadveh_gui.c saveload.c sdl.c
settings.c settings_gui.c ship_cmd.c ship_gui.c smallmap_gui.c
sound.c spritecache.c station_cmd.c station_gui.c
strings.c subsidy_gui.c texteff.c town_cmd.c town_gui.c
train_cmd.c train_gui.c tree_cmd.c ttd.c
tunnelbridge_cmd.c unmovable_cmd.c vehicle.c
viewport.c water_cmd.c widget.c window.c screenshot.c
airport.c grfspecial.c terraform_gui.c ;
LANGFILES = english.txt swedish.txt french.txt german.txt italian.txt slovak.txt hungarian.txt norwegian.txt danish.txt czech.txt galician.txt polish.txt;
####################
# On UNIX we use gcc
####################
if $(UNIX) {
SDL_CONFIG_CFLAGS = `XX_SDL_CONFIG_PLACEHOLDER_XX --cflags` ;
SDL_CONFIG_LIBS = `XX_SDL_CONFIG_PLACEHOLDER_XX --libs` ;
LINKFLAGS += $(SDL_CONFIG_LIBS) ;
CC = gcc ;
CCFLAGS += -Wall -Wno-multichar -DUNIX -DWITH_SDL ;
OPTIMFLAGS = -O2 -fomit-frame-pointer ;
DEBUGFLAGS = -g ;
# also include extmidi
CFILES += extmidi.c unix.c ;
# compile in PNG support?
if $(WITH_PNG) {
CCFLAGS += -DWITH_PNG -I$(WITH_PNG) ;
LINKFLAGS += -lpng ;
}
# compile in zlib support?
if $(WITH_ZLIB) {
CCFLAGS += -DWITH_ZLIB ;
LINKFLAGS += -lz ;
}
# compile for BeOS 5.1 and higher
if $(WITH_BONE_NETWORKING) {
CCFLAGS += -DENABLE_NETWORK ;
LINKFLAGS += -lsocket -lbind ;
}
# link in BeOS MIDI and Be API libraries
if $(BEOS_MIDI) {
CCFLAGS += -DBEOS_MIDI ;
LINKFLAGS += -lbe -lmidi ;
CFILES += bemidi.cpp ;
}
}
####################
# MSVC on Win32
####################
actions ActWin32Res {
$(VISUALC)\\..\\common\\msdev98\\bin\\rc /r /i $(STDHDRS) /fo $(<) $(>)
}
rule Win32Res { ActWin32Res $(<) : $(>) ; DEPENDS $(<) : $(>) ; }
if $(TOOLSET) = VISUALC {
OPTIMFLAGS = /Oa /Os /Ow /Oy /Oi /Og /Ox /Gr /Gf /Gy /Zp4 /J /WX /W3 -DNDEBUG ;
CCFLAGS += -DWIN32 -DWIN32_EXCEPTION_TRACKER ;
CFILES += win32.c ;
LINKFLAGS += /opt:nowin98 /LIBPATH:$(VISUALC)\\lib ;
LINKLIBS = ws2_32.lib winmm.lib user32.lib gdi32.lib ;
# compile resources too
EOBJ = ttd.res ;
Win32Res ttd.res : ttd.rc ;
# png screenshots?
if $(WITH_PNG) {
CCFLAGS += -DWITH_PNG -I$(WITH_PNG) ;
LINKLIBS += libpng.lib ;
}
# zlib savegames?
if $(WITH_ZLIB) {
CCFLAGS += -DWITH_ZLIB ;
LINKLIBS += zlibstat.lib ;
}
# build release by default
RELEASE = 1 ;
}
####################
# Common
####################
rule MyObjects {
local _i _t _s ;
_t = $(OUTDIR)/$(>:S=$(SUFOBJ)) ;
OPTIM on $(_t) = $(3) ;
MkDir $(OUTDIR) ;
Depends $(_t) : $(OUTDIR) ;
for _i in $(>) {
_s = $(OUTDIR)/$(_i:S=$(SUFOBJ)) ;
Object $(_s) : $(_i) ;
# special handling for sdl.c and unix.c
if $(_i) = sdl.c || $(_i) = unix.c { CCFLAGS on $(_s) += $(SDL_CONFIG_CFLAGS) ; }
}
MainFromObjects $(OUTDIR)/$(<) : $(_t) $(EOBJ) ;
}
rule MyMain {
if $(RELEASE) {
OUTDIR = release ;
MyObjects ttd : $(>) : $(OPTIMFLAGS) ;
} else {
OUTDIR = debug ;
MyObjects ttd : $(>) : -D_DEBUG $(DEBUGFLAGS) ;
}
}
actions CompileLang {
strgen$(SLASH)strgen $(>)
}
rule LangFile {
if $(>) = lang/english.txt {
CompileLang $(<) table/strings.h : ;
DEPENDS table/string.h : $(>) ;
} else {
CompileLang $(<) : $(>) ;
}
Clean clean : $(<) ;
DEPENDS $(<) : $(>) ;
DEPENDS all : $(<) ;
DEPENDS $(<) : strgen/strgen ;
}
rule LangFiles {
local _i ;
for _i in $(<) { LangFile $(_i:S=.lng) : $(_i) ; }
Clean clean : table/strings.h ;
}
LangFiles lang/$(LANGFILES) ;
Main strgen/strgen : strgen/strgen.c ;
MyMain ttd : $(CFILES) ;

@ -0,0 +1,615 @@
# This Makefile is partially based on "a completely generic Makefile",
# originally created by Justin Husted <husted@cs>
#
# Rewrite and sane dependencies support by Petr Baudis <pasky@ucw.cz>
# Cygwin support and configuration by Jaen Saul <slowbyte@hot.ee>
# A lot of modifications by Bjarni Corfitzen <bjarni@openttd.com>
#
# Last modified by: $Author: strigeus $
# On: $Date: 2004/03/11 19:15:06 $
##############################################################################
#
# Usage
#
# Synopsis:
#
# make WITH_ZLIB=1 UNIX=1 MANUAL_CONFIG=1
#
# (See below for the list of possible options.)
#
# Alternately, you can run make without the MANUAL_CONFIG part. It then
# generates Makefile.config, where you can customize all the options.
# However beware that for all subsequent calls the option values from
# Makefile.config take precedence to the commandline options.
#
# (That means that you probably want to either specify the options on command
# line together with MANUAL_CONFIG=1 or you want to specify no commandline
# options at all.)
# Targets:
#
# Defaults to building binary
# clean: remove intermediate build files
# mrproper: remove intermediate files and makefile configuration
# upgradeconf: add new options to old Makefile.config
# osx: OS X application
# Options:
#
# Summary of OS choice defines
# WIN32: building on Windows
# UNIX: building on *nix derivate (Linux, FreeBSD)
# OSX: building on Mac OS X
# MORPHOS: building on MorphOS
#
# Summary of library choice defines
# WITH_ZLIB: savegames using zlib
# WITH_PNG: screenshots using PNG
# WITH_SDL: SDL video driver support
#
# Summary of other defines:
# MANUAL_CONFIG: do not use Makefile.config, config options set manually
# DEBUG: build in debug mode
# PROFILE: build in profile mode, disables -s and -fomit-frame-pointer
# DISPLAY_WARNINGS: when off, some errors are not displayed while compiling
# TRANSLATOR: build in translator mode (untranslated strings are prepended by
# a <TODO> mark)
# RELEASE: this will be the released version number. It replaces all places
# where it normally would print the revision number
# MIDI: if set, it will use it as custom path to midi player.
# If unset, it will use the hardcoded path in the c code
#
# DATA_DIR_PREFIX: This sets the dir OpenTTD looks for the needed files.
# MUST END WITH / if defined
#
# STATIC: link statically
# CYGWIN: build in Cygwin environment
# MINGW: build with MingW compiler, link with MingW libraries
#
# Experimental (does not work properly):
# WITH_NETWORK: enable networking
# WITH_DIRECTMUSIC: enable DirectMusic MIDI support
##############################################################################
#
# Configuration
#
# CONFIG_WRITER have to be found even for manual configuration
CONFIG_WRITER=makefiledir/Makefile.config_writer
ifndef MANUAL_CONFIG
# Automatic configuration
MAKE_CONFIG:=Makefile.config
MAKEFILE:=Makefile
LIB_DETECTION=makefiledir/Makefile.libdetection
CONFIG_WRITER=makefiledir/Makefile.config_writer
# Apply automatic configuration
# See target section for how this is built, suppress errors
# since first time it isn't found but make reads this twice
-include $(MAKE_CONFIG)
else
CONFIG_INCLUDED:=1
endif
# tests if makefile.config contains the new needed SDL-CONFIG
# it updates makefile.config if needed. Flags like ENABLE_NETWORK are remembered
ifndef SDL-CONFIG
ifdef WITH_SDL
ifndef MANUAL_CONFIG
#network is enabled by default
ENABLE_NETWORK:=1
UPDATECONFIG:=upgradeconf
CONFIG_INCLUDED:=
else
# this should define SDL-CONFIG for manual configuration
ifeq ($(shell uname),FreeBSD)
SDL-CONFIG:=sdl11-config
else
SDL-CONFIG:=sdl-config
endif
endif
endif
endif
ifndef CONFIG_INCLUDED
-include $(LIB_DETECTION)
endif
ifdef DISPLAY_WARNINGS
WARNING_DISPLAY:=-fstrict-aliasing
else
WARNING_DISPLAY:=-fno-strict-aliasing
endif
ifdef STATIC
ifndef WIN32
ifndef OSX
ifndef MORPHOS
ifndef SKIP_STATIC_CHECK
$(error Static is only known to work on MorphOS and MacOSX!!! --- Check makefile.config for more info and howto bypass this check)
endif
endif
endif
endif
endif
# Force SDL on UNIX platforms
ifndef WITH_SDL
ifdef UNIX
$(error You need to have SDL installed in order to run OpenTTD on UNIX.)
endif
endif
##############################################################################
#
# Compiler configuration
#
CC=gcc
CXX=g++
ifdef MORPHOS
CC += -noixemul -pipe
CXX += -noixemul -pipe
endif
# Executable file extension
ifdef WIN32
EXE=.exe
else
EXE=
endif
# Set output executable names
TTD=ttd$(EXE)
STRGEN=strgen/strgen$(EXE)
OSXAPP="OpenTTD.app"
# What revision are we compiling, if we have an idea?
REV_NUMBER := $(shell if test -d .svn; then svnversion . | tr -dc 0-9; fi)
ifdef RELEASE
REV:=$(RELEASE)
else
REV := $(shell if test -d .svn; then echo -n r; svnversion .; fi)
tmp_test:=$(shell echo "$(REV)" | grep "M" )
ifdef tmp_test
REV_NUMBER:=1
endif
endif
ifndef REV_NUMBER
REV_NUMBER:=0
endif
# MorphOS needs builddate
BUILDDATE=`date +%d.%m.%y`
# AMD64 needs a little more settings to work
ifeq ($(shell uname -m), x86_64)
endwarnings:=endwarnings
64_bit_warnings:=64_bit_warnings
BASECFLAGS += -m64 -D_LITTLE_ENDIAN
endif
# When calling the compiler, use these flags
# -g debugging symbols
# -Wall all warnings
# -s automatic strip
#
# You may also want:
# -O optimize or -O2 fully optimize (O's above 2 are not recommended)
# -pg profile - generate profiling data. See "man gprof" to use this.
CFLAGS=-Wall -Wno-multichar
CDEFS=-DWITH_REV
LDFLAGS=
LIBS=
ifdef DEBUG
# Debug mode
CDEFS += -D_DEBUG
BASECFLAGS += -g
else
ifdef PROFILE
BASECFLAGS += -pg
else
# Release mode
ifndef MORPHOS
# automatical strip breaks under morphos
BASECFLAGS += -s
LDFLAGS += -s
endif
endif
ifdef OSX
# these compilerflags makes the app run as fast as possible without making the app unstable. It works on G3 or newer
BASECFLAGS += -O3 -funroll-loops -fsched-interblock -falign-loops=16 -falign-jumps=16 -falign-functions=16 -falign-jumps-max-skip=15 -falign-loops-max-skip=15 -mdynamic-no-pic -mpowerpc-gpopt -force_cpusubtype_ALL $(WARNING_DISPLAY)
else
ifdef MORPHOS
BASECFLAGS += -O2 -funroll-loops -fexpensive-optimizations -mstring -mmultiple $(WARNING_DISPLAY)
else
BASECFLAGS += -O2 $(WARNING_DISPLAY)
endif
ifndef PROFILE
BASECFLAGS += -fomit-frame-pointer
endif
endif
endif
ifdef STATIC
ifndef OSX # OSX can't build static if -static flag is used
LDFLAGS += -static
endif
endif
# If building on Cygwin/MingW don't link with Cygwin libs
ifdef WIN32
ifdef MINGW
ifdef CYGWIN
BASECFLAGS += -mno-cygwin
LDFLAGS += -mno-cygwin
endif
endif
endif
CFLAGS += $(BASECFLAGS)
ifdef UNIX
CDEFS += -DUNIX
endif
# SDL config
ifdef WITH_SDL
CDEFS += -DWITH_SDL
CFLAGS += `$(SDL-CONFIG) --cflags`
ifdef STATIC
LIBS += `$(SDL-CONFIG) --static-libs`
else
LIBS += `$(SDL-CONFIG) --libs`
endif
endif
# zlib config
ifdef WITH_ZLIB
CDEFS += -DWITH_ZLIB
ifdef STATIC
ifdef OSX
# zlib is default on OSX, so everybody have it. No need for static linking
LIBS += -lz
else
ifndef STATIC_ZLIB_PATH
ifndef MANUAL_CONFIG
# updates makefile.config with the zlib path
UPDATECONFIG:=upgradeconf
endif
TEMP:=$(shell ls /lib 2>/dev/null | grep "zlib.a")$(shell ls /lib 2>/dev/null | grep "libz.a")
ifdef TEMP
STATIC_ZLIB_PATH:=/lib/$(TEMP)
else
TEMP:=$(shell ls /usr/lib 2>/dev/null | grep "zlib.a")$(shell ls /usr/lib 2>/dev/null | grep "libz.a")
ifdef TEMP
STATIC_ZLIB_PATH:=/usr/lib/$(TEMP)
else
TEMP:=$(shell ls /usr/local/lib 2>/dev/null | grep "zlib.a")$(shell ls /usr/local/lib 2>/dev/null | grep "libz.a")
ifdef TEMP
STATIC_ZLIB_PATH:=/usr/local/lib/$(TEMP)
endif
endif
endif
endif
LIBS += $(STATIC_ZLIB_PATH)
endif
else
LIBS += -lz
endif
endif
# libpng config
ifdef WITH_PNG
CDEFS += -DWITH_PNG
# FreeBSD doesn't use libpng-config
ifdef FREEBSD
LIBS += -lpng
else
CFLAGS += `libpng-config --cflags`
ifdef OSX
ifdef STATIC
# Seems like we need a tiny hack for OSX static to work
LIBS += `libpng-config --prefix`/lib/libpng.a
else
LIBS += `libpng-config --libs`
endif
else
# seems like older libpng versions are broken and need this
PNGCONFIG_FLAGS = --ldflags --libs
ifdef STATIC
LIBS += `libpng-config --static $(PNGCONFIG_FLAGS)`
else
LIBS += `libpng-config $(PNGCONFIG_FLAGS)`
endif
endif
endif
endif
ifdef TRANSLATOR
STRGEN_FLAGS=-t
else
STRGEN_FLAGS=
endif
# file paths setup
ifdef GAME_DATA_DIR
CDEFS += -DGAME_DATA_DIR=\"$(GAME_DATA_DIR)\"
endif
ifdef PERSONAL_DIR
CDEFS += -DPERSONAL_DIR=\"$(PERSONAL_DIR)\"
endif
ifdef USE_HOMEDIR
CDEFS += -DUSE_HOMEDIR
endif
# MIDI setup
ifdef OSX
ifndef MIDI
MIDI:=$(OSXAPP)/contents/macos/track_starter
endif
endif
ifdef MIDI
CDEFS += -DEXTERNAL_PLAYER=\"$(MIDI)\"
ifdef MIDI_ARG
CDEFS += -DMIDI_ARG=\"$(MIDI_ARG)\"
endif
endif
# Experimental
ifdef WITH_NETWORK
CDEFS += -DENABLE_NETWORK
ifdef UNIX
ifndef OSX
ifndef MORPHOS
# this have caused problems on many platforms and disabling it didn't break anything
# now we test if disabling it as a general breaks it for anybody
#LIBS += -lresolv
endif
endif
endif
endif
ifdef WITH_DIRECTMUSIC
CDEFS += -DWIN32_ENABLE_DIRECTMUSIC_SUPPORT
endif
ifdef WIN32
LIBS += -lws2_32 -lwinmm -lgdi32 -ldxguid -lole32 -lstdc++
TTDLDFLAGS += -Wl,--subsystem,windows
endif
# sets up the paths for use for make install
ifdef BINARY_DIR
BINARY_INSTALL:=$(BINARY_DIR)$(TTD)
else
BINARY_INSTALL:=$(INSTALL_DIR)$(TTD)
endif
ifdef DATA_DIR_PREFIX
DATA_DIR:=$(DATA_DIR_PREFIX)
else
DATA_DIR:=$(INSTALL_DIR)
endif
##############################################################################
#
# What to compile
# (users do not want to modify anything below)
#
### Sources
ttd_SOURCES = \
ai.c aircraft_cmd.c aircraft_gui.c airport.c airport_gui.c bridge_gui.c \
clear_cmd.c command.c disaster_cmd.c dock_gui.c dummy_land.c economy.c \
engine.c engine_gui.c fileio.c gfx.c graph_gui.c industry_cmd.c \
industry_gui.c intro_gui.c landscape.c main_gui.c misc.c misc_cmd.c \
misc_gui.c music_gui.c namegen.c network.c news_gui.c oldloader.c \
order_cmd.c order_gui.c pathfind.c player_gui.c players.c rail_cmd.c \
rail_gui.c road_cmd.c road_gui.c roadveh_cmd.c roadveh_gui.c saveload.c \
settings_gui.c ship_cmd.c ship_gui.c smallmap_gui.c sound.c \
spritecache.c station_cmd.c station_gui.c strings.c subsidy_gui.c \
texteff.c town_cmd.c town_gui.c train_cmd.c train_gui.c tree_cmd.c \
ttd.c tunnelbridge_cmd.c unmovable_cmd.c vehicle.c viewport.c \
water_cmd.c widget.c window.c minilzo.c screenshot.c settings.c rev.c \
grfspecial.c terraform_gui.c network_gui.c
ifdef WITH_SDL
ttd_SOURCES += sdl.c
endif
ifdef WIN32
ttd_SOURCES += win32.c w32dm.c
else
ttd_SOURCES += extmidi.c unix.c
endif
ttd_OBJS = $(ttd_SOURCES:%.c=%.o)
ifdef WIN32
# Resource file
ttd_OBJS += winres.o
endif
ifdef WITH_DIRECTMUSIC
ttd_SOURCES += w32dm2.cpp
ttd_OBJS += w32dm2.o
endif
ttd_DEPS1 = $(foreach obj,$(ttd_OBJS),.deps/$(obj))
ttd_DEPS = $(ttd_DEPS1:%.o=%.P)
LANG_TXT = $(filter-out %.unfinished.txt,$(wildcard lang/*.txt))
LANGS = $(LANG_TXT:%.txt=%.lng)
C_COMPILE = $(CC) $(CFLAGS) $(CDEFS)
CXX_COMPILE = $(CXX) $(CFLAGS) $(CDEFS)
C_BUILD = $(C_COMPILE) -c
CXX_BUILD = $(CXX_COMPILE) -c
C_LINK = $(CC) $(LDFLAGS) -o
##############################################################################
#
# Targets
#
### Normal build rules
ifdef OSX
OSX:=OSX
endif
all: $(UPDATECONFIG) $(TTD) $(OSX) $(endwarnings)
$(TTD): table/strings.h $(ttd_OBJS) $(LANGS) $(MAKE_CONFIG)
$(C_LINK) $@ $(TTDLDFLAGS) $(ttd_OBJS) $(LIBS)
$(OSX):
@mkdir -p $(OSXAPP)/Contents/MacOS
@mkdir -p $(OSXAPP)/Contents/Resources
@echo "APPL????" > $(OSXAPP)/Contents/PkgInfo
@cp os/macos/ttd.icns $(OSXAPP)/Contents/Resources/
@os/macos/plistgen.sh $(OSXAPP) $(REV)
@cp os/macos/track_starter $(OSXAPP)/contents/macos
@ls os/macos | grep -q "\.class" || \
javac os/macos/OpenTTDMidi.java
@cp os/macos/OpenTTDMidi.class $(OSXAPP)/contents/macos
@cp $(TTD) $(OSXAPP)/Contents/MacOS/ttd
$(endwarnings): $(64_bit_warnings)
$(64_bit_warnings):
$(warning 64 bit CPUs will get some 64 bit specific bugs!)
$(warning If you see any bugs, include in your bug report that you use a 64 bit CPU)
$(STRGEN): strgen/strgen.c rev.o
$(CC) $(BASECFLAGS) $(CDEFS) -o $@ $^
lang/english.lng: lang/english.txt $(STRGEN)
$(STRGEN)
table/strings.h: lang/english.lng
lang/%.lng: lang/%.txt $(STRGEN)
$(STRGEN) $(STRGEN_FLAGS) $<
winres.o: ttd.rc
windres -o $@ $<
rev.c: FORCE
@# setting the revision number in a place, there the binary can read it
@echo 'const char _openttd_revision[] = "'$(REV)'";' >>rev.c.new
@echo 'const int _revision_number = $(REV_NUMBER);' >>rev.c.new
@# some additions for MorphOS versions tag
@echo '#ifdef __MORPHOS__' >>rev.c.new
@echo 'const char morphos_versions_tag[] = "\\0$$VER: OpenTTD '$(REV)' ('${BUILDDATE}') © OpenTTD Team [MorphOS, PowerPC]";' >>rev.c.new
@echo '#endif' >>rev.c.new
@# Only update the real rev.c if it actually changed, to prevent
@# useless rebuilds.
@cmp -s rev.c rev.c.new 2>/dev/null || mv rev.c.new rev.c
@rm -f rev.c.new
FORCE:
clean:
rm -rf .deps *~ $(TTD) $(STRGEN) core table/strings.h $(LANGS) $(ttd_OBJS)
mrproper: clean
rm -rf $(MAKE_CONFIG)
ifndef OSX
ifndef MORPHOS
install:
@if [ "$(INSTALL)" == "" ]; then $(error make install is highly experimental at his state and not\
tested very much - use at your own risk - to use run \"make install INSTALL:=1\" - make sure makefile.config\
is set correctly up - run \"make upgradeconf\")
@if [ "$(DATA_DIR)" == "" ]; then $(error no install path set - check makefile.config)
mkdir -p $(DATA_DIR)/lang
mkdir -p $(DATA_DIR)/data
cp $(TTD) $(BINARY_INSTALL)
cp lang/*.lng $(DATA_DIR)/lang
cp data/*.grf $(DATA_DIR)/data
else #MorphOS
install:
$(error make install is not supported on MorphOS)
endif
else # OSX
install:
$(error make install is not supported on MacOSX)
endif
love:
@echo "YES! I thought you would never ask. We will have a great time. You can keep me turned on all night"
.PHONY: clean all $(OSX) install $(64_bit_warnings) $(endwarnings) love
### Automatic configuration
-include $(CONFIG_WRITER)
# Export all variables set to subprocesses (a bit dirty)
.EXPORT_ALL_VARIABLES:
upgradeconf: $(MAKE_CONFIG)
rm $(MAKE_CONFIG)
$(MAKE) $(MAKE_CONFIG)
.PHONY: upgradeconf
### Internal build rules
# This makes sure the .deps dir is always around.
DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :)
# Introduce the dependencies
-include $(ttd_DEPS)
# This compiles the object file as well as silently updating its dependencies
# list at the same time. It is not an issue that they aren't around during the
# first compilation round as we just build everything at that time anyway,
# therefore we do not need to watch deps.
%.o: %.c $(MAKE_CONFIG)
@echo '$(C_BUILD) $<'; \
$(C_BUILD) $< -Wp,-MD,.deps/$(*F).pp
@-cp .deps/$(*F).pp .deps/$(*F).P; \
tr ' ' '\012' < .deps/$(*F).pp \
| sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
>> .deps/$(*F).P; \
rm .deps/$(*F).pp
# For DirectMusic build
%.o: %.cpp $(MAKE_CONFIG)
$(CXX_BUILD) $<

@ -0,0 +1,8 @@
// 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

3943
ai.c

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,283 @@
#include "stdafx.h"
#include "airport.h"
AirportFTAClass *CountryAirport;
AirportFTAClass *CityAirport;
AirportFTAClass *Heliport, *Oilrig;
AirportFTAClass *MetropolitanAirport;
AirportFTAClass *InternationalAirport;
static void AirportFTAClass_Constructor(AirportFTAClass *Airport,
const byte nofterminals, const byte nofterminalgroups,
const byte nofhelipads, const byte nofhelipadgroups,
const byte entry_point, const byte acc_planes,
const AirportFTAbuildup *FA,
const TileIndex *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()
{
// country airport
CountryAirport = (AirportFTAClass *)malloc(sizeof(AirportFTAClass));
AirportFTAClass_Constructor(CountryAirport, 2, 1, 0, 0, 16, ALL, _airport_fta_country, _airport_depots_country);
// city airport
CityAirport = (AirportFTAClass *)malloc(sizeof(AirportFTAClass));
AirportFTAClass_Constructor(CityAirport, 3, 1, 0, 0, 19, ALL, _airport_fta_city, _airport_depots_city);
// metropolitan airport
MetropolitanAirport = (AirportFTAClass *)malloc(sizeof(AirportFTAClass));
AirportFTAClass_Constructor(MetropolitanAirport, 3, 1, 0, 0, 20, ALL, _airport_fta_metropolitan, _airport_depots_metropolitan);
// international airport
InternationalAirport = (AirportFTAClass *)malloc(sizeof(AirportFTAClass));
AirportFTAClass_Constructor(InternationalAirport, 6, 2, 2, 1, 37, ALL, _airport_fta_international, _airport_depots_international);
// heliport, oilrig
Heliport = (AirportFTAClass *)malloc(sizeof(AirportFTAClass));
AirportFTAClass_Constructor(Heliport, 0, 0, 1, 1, 7, HELICOPTERS_ONLY, _airport_fta_heliport_oilrig, _airport_depots_heliport_oilrig);
Oilrig = Heliport; // exactly the same structure for heliport/oilrig, so share state machine
}
void UnInitializeAirports()
{
AirportFTAClass_Destructor(CountryAirport);
AirportFTAClass_Destructor(CityAirport);
AirportFTAClass_Destructor(Heliport);
AirportFTAClass_Destructor(MetropolitanAirport);
AirportFTAClass_Destructor(InternationalAirport);
}
static void AirportFTAClass_Constructor(AirportFTAClass *Airport,
const byte nofterminals, const byte nofterminalgroups,
const byte nofhelipads, const byte nofhelipadgroups,
const byte entry_point, const byte acc_planes,
const AirportFTAbuildup *FA,
const TileIndex *depots)
{
// 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
if (nofterminalgroups > nofterminals) { printf("# of terminalgroups (%2d) must be less or equal to terminals (%2d)", nofterminals, nofterminalgroups);}
if (nofhelipadgroups > nofhelipads) { printf("# of helipadgroups (%2d) must be less or equal to helipads (%2d)", nofhelipads, nofhelipadgroups);}
assert(nofterminals <= MAX_TERMINALS);
assert(nofhelipads <= MAX_HELIPADS);
assert(nofterminalgroups <= nofterminals);
assert(nofhelipadgroups <= nofhelipads);
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->nofterminals = nofterminals;
Airport->nofterminalgroups = nofterminalgroups;
Airport->nofhelipads = nofhelipads;
Airport->nofhelipadgroups = nofhelipadgroups;
Airport->acc_planes = acc_planes;
Airport->entry_point = entry_point;
Airport->airport_depots = (uint16*)depots;
// build the state machine
AirportBuildAutomata(Airport, FA);
//#ifdef _DEBUG
// {printf("#Elements %2d; #Terminals %2d in %d group(s); #Helipads %2d in %d group(s)\n", Airport->nofelements,
// Airport->nofterminals, Airport->nofterminalgroups, Airport->nofhelipads, Airport->nofhelipadgroups);}
//#endif
{
byte _retval = AirportTestFTA(Airport);
if (_retval != MAX_ELEMENTS) {printf("ERROR with element: %d\n", _retval-1);}
assert(_retval == 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 = (AirportFTA *)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 = (AirportFTA *)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;
}
static const char* const _airport_heading_strings[MAX_HEADINGS+2] = {
"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;
}*/
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;
}

@ -0,0 +1,52 @@
#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 = 5
};
// 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
byte nofterminals; // number of terminals this airport has
byte nofterminalgroups; // terminals belong to so many groups (MAX is the nofterminals)
byte nofhelipads; // number of helipads this airport has
byte nofhelipadgroups; // helipads belong to so many groups (MAX is the nofhelipads)
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
uint16 *airport_depots; // gives the position of the depots on the airports
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 UnInitializeAirports();
const AirportFTAClass* GetAirport(const byte airport_type);
#endif /* AIRPORT_H */

@ -0,0 +1,227 @@
#include "stdafx.h"
#include "ttd.h"
#include "window.h"
#include "gui.h"
#include "viewport.h"
#include "gfx.h"
#include "command.h"
#include "vehicle.h"
#include "station.h"
#include "airport.h"
static byte _selected_airport_type;
static void ShowBuildAirportPicker();
static void CcBuildAirport(bool success, uint tile, uint32 p1, uint32 p2)
{
if (success) {
SndPlayTileFx(0x1D, tile);
ResetObjectToPlace();
}
}
static void PlaceAirport(uint tile)
{
DoCommandP(tile, _selected_airport_type, 0, CcBuildAirport, CMD_BUILD_AIRPORT | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_A001_CAN_T_BUILD_AIRPORT_HERE));
}
static void PlaceAir_DemolishArea(uint tile)
{
VpStartPlaceSizing(tile, 4);
}
static void BuildAirClick_Airport(Window *w)
{
if (HandlePlacePushButton(w, 2, 0xAA4, 1, PlaceAirport)) ShowBuildAirportPicker();
}
static void BuildAirClick_Demolish(Window *w)
{
HandlePlacePushButton(w, 3, ANIMCURSOR_DEMOLISH, 1, PlaceAir_DemolishArea);
}
static void BuildAirClick_Lower(Window *w)
{
HandlePlacePushButton(w, 4, ANIMCURSOR_LOWERLAND, 2, PlaceProc_LowerLand);
}
static void BuildAirClick_Raise(Window *w)
{
HandlePlacePushButton(w, 5, ANIMCURSOR_RAISELAND, 2, PlaceProc_RaiseLand);
}
static void BuildAirClick_Purchase(Window *w)
{
HandlePlacePushButton(w, 6, 0x12B8, 1, PlaceProc_BuyLand);
}
typedef void OnButtonClick(Window *w);
static OnButtonClick * const _build_air_button_proc[] = {
BuildAirClick_Airport,
BuildAirClick_Demolish,
BuildAirClick_Lower,
BuildAirClick_Raise,
BuildAirClick_Purchase,
};
static void BuildAirToolbWndProc(Window *w, WindowEvent *e)
{
switch(e->event) {
case WE_PAINT:
DrawWindowWidgets(w);
break;
case WE_CLICK:
if (e->click.widget-2 >= 0)
_build_air_button_proc[e->click.widget - 2](w);
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:
w->click_state = 0;
SetWindowDirty(w);
w = FindWindowById(WC_BUILD_STATION, 0);
if (w != 0)
WP(w,def_d).close = true;
break;
}
}
static const Widget _air_toolbar_widgets[] = {
{ WWT_CLOSEBOX, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, 7, 11, 129, 0, 13, STR_A000_AIRPORT_CONSTRUCT, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PANEL, 7, 0, 41, 14, 35, 0x2E8, STR_A01E_BUILD_AIRPORT},
{ WWT_PANEL, 7, 42, 63, 14, 35, 0x2BF, STR_018D_DEMOLISH_BUILDINGS_ETC},
{ WWT_PANEL, 7, 64, 85, 14, 35, 0x2B7, STR_018E_LOWER_A_CORNER_OF_LAND},
{ WWT_PANEL, 7, 86, 107, 14, 35, 0x2B6, STR_018F_RAISE_A_CORNER_OF_LAND},
{ WWT_PANEL, 7, 108, 129, 14, 35, 0x12B7, STR_0329_PURCHASE_LAND_FOR_FUTURE},
{ WWT_LAST},
};
static const WindowDesc _air_toolbar_desc = {
510, 22, 130, 36,
WC_BUILD_TOOLBAR,0,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
_air_toolbar_widgets,
BuildAirToolbWndProc
};
void ShowBuildAirToolbar()
{
DeleteWindowById(WC_BUILD_TOOLBAR, 0);
AllocateWindowDescFront(&_air_toolbar_desc, 0);
}
static void BuildAirportPickerWndProc(Window *w, WindowEvent *e)
{
switch(e->event) {
case WE_PAINT: {
int sel;
if (WP(w,def_d).close)
return;
w->disabled_state = 0;
sel = _selected_airport_type;
// FIXME -- BuildAirportPickerWndProc - set availability of airports by year, instead of airplane
if (!(_avail_aircraft & 1)) { w->disabled_state |= (1<<3); if (sel == AT_SMALL) sel = AT_LARGE; }
if (!(_avail_aircraft & 2)) { w->disabled_state |= (1<<4); if (sel == AT_LARGE) sel = AT_SMALL; }
if (!(_avail_aircraft & 4)) { w->disabled_state |= (1<<5); } // heliport
// 1980-1-1 is --> 21915
// 1990-1-1 is --> 25568
if (_date < 21915) {w->disabled_state |= (1<<6);} // metropilitan airport 1980
if (_date < 25568) {w->disabled_state |= (1<<7);} // international airport 1990
_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 (_station_show_coverage) SetTileSelectBigSize(-4, -4, 8, 8);
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);
break;
}
case WE_CLICK: {
switch(e->click.widget) {
case 0:
ResetObjectToPlace();
break;
case 3: case 4: case 5: case 6: case 7:
_selected_airport_type = e->click.widget - 3;
SndPlayFx(0x13);
SetWindowDirty(w);
break;
case 8: case 9:
_station_show_coverage = e->click.widget - 8;
SndPlayFx(0x13);
SetWindowDirty(w);
break;
}
} break;
case WE_MOUSELOOP: {
if (WP(w,def_d).close) {
DeleteWindow(w);
return;
}
CheckRedrawStationCoverage(w);
} break;
}
}
static const Widget _build_airport_picker_widgets[] = {
{ WWT_CLOSEBOX, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, 7, 11, 147, 0, 13, STR_3001_AIRPORT_SELECTION, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PANEL, 7, 0, 147, 14, 130, 0x0, 0},
{WWT_NODISTXTBTN, 14, 2, 73, 27, 38, STR_3059_SMALL, STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
{WWT_NODISTXTBTN, 14, 74, 145, 27, 38, STR_305A_LARGE, STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
{WWT_NODISTXTBTN, 14, 2, 145, 63, 74, STR_306B_HELIPORT, STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
{WWT_NODISTXTBTN, 14, 2, 145, 39, 50, STR_305AA_LARGE, STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
{WWT_NODISTXTBTN, 14, 2, 145, 51, 62, STR_305AB_LARGE, STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
{ WWT_CLOSEBOX, 14, 14, 73, 88, 98, STR_02DB_OFF, STR_3065_DON_T_HIGHLIGHT_COVERAGE},
{ WWT_CLOSEBOX, 14, 74, 133, 88, 98, STR_02DA_ON, STR_3064_HIGHLIGHT_COVERAGE_AREA},
{ WWT_LAST},
};
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()
{
AllocateWindowDesc(&_build_airport_desc);
}
void InitializeAirportGui()
{
_selected_airport_type = AT_SMALL;
_last_built_aircraft_depot_tile = 0;
}

@ -0,0 +1,456 @@
#ifndef AIRPORT_MOVEMENT_H
#define AIRPORT_MOVEMENT_H
#include "stdafx.h"
#include "macros.h"
// don't forget to change the airport_depots too for larger mapsizes. TILE_X_BITS 16
// won't fit in uint16 for example and overflow will occur in the checking code!
// TrueLight -- So make it a TileIndex..
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,}, // 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 TileIndex _airport_depots_country[] = {1, TILE_XY(3,0)};
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 TileIndex _airport_depots_city[] = {1, TILE_XY(5,0)};
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 TileIndex _airport_depots_metropolitan[] = {1, TILE_XY(5,0)};
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 TileIndex _airport_depots_international[] = {2, TILE_XY(0,3), TILE_XY(6,1)};
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
};
static const TileIndex _airport_depots_heliport_oilrig[] = {0};
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[6] = {
_airport_moving_data_country, // Country Airfield (small) 4x3
_airport_moving_data_town, // City Airport (large) 6x6
_airport_moving_data_heliport, // Heliport
_airport_moving_data_metropolitan, // Metropolitain Airport (large) - 2 runways
_airport_moving_data_international, // International Airport (xlarge) - 2 runways
_airport_moving_data_oilrig // Oilrig
};
#endif /* AIRPORT_MOVEMENT_H */

@ -0,0 +1,55 @@
#ifdef __BEOS__
#include "stdafx.h"
#include "ttd.h"
#include "hal.h"
// BeOS System Includes
#include <MidiSynthFile.h>
BMidiSynthFile midiSynthFile;
static char *bemidi_start(char **parm) {
return NULL;
}
static void bemidi_stop(void) {
midiSynthFile.UnloadFile();
}
static void bemidi_play_song(const char *filename) {
bemidi_stop();
entry_ref midiRef;
get_ref_for_path(filename, &midiRef);
midiSynthFile.LoadFile(&midiRef);
midiSynthFile.Start();
}
static void bemidi_stop_song(void) {
midiSynthFile.UnloadFile();
}
static bool bemidi_is_playing(void) {
if(midiSynthFile.IsFinished() == true)
{
return 0;
} else {
return 1;
}
}
static void bemidi_set_volume(byte vol) {
fprintf(stderr, "BeMidi: Set volume not implemented\n");
}
const HalMusicDriver _bemidi_music_driver = {
bemidi_start,
bemidi_stop,
bemidi_play_song,
bemidi_stop_song,
bemidi_is_playing,
bemidi_set_volume,
};
#endif // __BEOS__

@ -0,0 +1,164 @@
#include "stdafx.h"
#include "ttd.h"
#include "window.h"
#include "gui.h"
#include "viewport.h"
#include "gfx.h"
#include "command.h"
static struct BridgeData {
int count;
TileIndex start_tile;
TileIndex end_tile;
byte type;
byte indexes[MAX_BRIDGES];
int32 costs[MAX_BRIDGES];
} _bridge;
extern const uint16 _bridge_type_price_mod[MAX_BRIDGES];
extern const PalSpriteID _bridge_sprites[MAX_BRIDGES];
extern const uint16 _bridge_speeds[MAX_BRIDGES];
extern const StringID _bridge_material[MAX_BRIDGES];
static void CcBuildBridge(bool success, uint tile, uint32 p1, uint32 p2)
{
if (success) { SndPlayTileFx(0x25, tile); }
}
static void BuildBridge(Window *w, int i)
{
DeleteWindow(w);
DoCommandP(_bridge.end_tile, _bridge.start_tile, _bridge.indexes[i] | (_bridge.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: {
int i;
DrawWindowWidgets(w);
for(i=0; i < 4 && i + w->vscroll.pos < _bridge.count; i++) {
int ind = _bridge.indexes[i + w->vscroll.pos];
SET_DPARAM32(2, _bridge.costs[i + w->vscroll.pos]);
SET_DPARAM16(1, (_bridge_speeds[ind] >> 4) * 10);
SET_DPARAM16(0, _bridge_material[ind]);
DrawSprite(_bridge_sprites[ind], 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 < (uint)_bridge.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) < (uint)_bridge.count)
BuildBridge(w, ind);
}
break;
}
}
static const Widget _build_bridge_widgets[] = {
{ WWT_CLOSEBOX, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, 7, 11, 199, 0, 13, STR_100D_SELECT_RAIL_BRIDGE, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_MATRIX, 7, 0, 188, 14, 101, 0x401, STR_101F_BRIDGE_SELECTION_CLICK},
{ WWT_SCROLLBAR, 7, 189, 199, 14, 101, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
{ WWT_LAST},
};
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, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, 7, 11, 199, 0, 13, STR_1803_SELECT_ROAD_BRIDGE, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_MATRIX, 7, 0, 188, 14, 101, 0x401, STR_101F_BRIDGE_SELECTION_CLICK},
{ WWT_SCROLLBAR, 7, 189, 199, 14, 101, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
{ WWT_LAST},
};
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(uint start, uint end, byte bridge_type)
{
int j = 0;
int32 ret;
uint16 errmsg;
DeleteWindowById(WC_BUILD_BRIDGE, 0);
_bridge.type = bridge_type;
_bridge.start_tile = start;
_bridge.end_tile = end;
errmsg = 0xFFFF;
// 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 (ret == CMD_ERROR) {
errmsg = _error_message;
}
// check which bridges can be built
else {
int bridge_len; // length of the middle parts of the bridge
int tot_bridge_len; // total length of bridge
// get absolute bridge length
bridge_len = GetBridgeLength(start, end);
tot_bridge_len = bridge_len + 2;
tot_bridge_len = CalcBridgeLenCostFactor(tot_bridge_len);
for (bridge_type = 0; bridge_type != MAX_BRIDGES; bridge_type++) { // loop for all bridgetypes
if (CheckBridge_Stuff(bridge_type, bridge_len)) {
// bridge is accepted, add to list
// add to terraforming & bulldozing costs the cost of the bridge itself (not computed with DC_QUERY_COST)
_bridge.costs[j] = ret + (((tot_bridge_len * _price.build_bridge) * _bridge_type_price_mod[bridge_type]) >> 8);
_bridge.indexes[j] = bridge_type;
j++;
}
}
}
_bridge.count = j;
if (j != 0) {
Window *w = AllocateWindowDesc((_bridge.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, GET_TILE_X(end) * 16, GET_TILE_Y(end) * 16);
}
}

@ -0,0 +1,439 @@
0.3.3 (2004-07-13)
------------------------------------------------------------------------
- Feature: (MorphOS/AmigaOS) network support
- Feature: improved german town name generator
- Change: scenarios now have the file extension .scn
- Fix: removing and upgrading tracks under a bridge when a train is on the bridge
- Change: default network port from 12345 (known trojan) to 3979
- Fix: pause button was not synched in network games
- Fix: crash caused by invalid screen resolutions
- Fix: AI can not build tubular bridges in 1950, etc. Same restrictions apply to it, as to human players.
- Feature: transparent station signs
- Feature: show total cargo per wagon type in train details window
- Fix: volume, liters, was x100, should be x1000
- Feature: bridges on slopes
- Fix: bridge building by towns was screwed when executed without testing first
- Feature: added Galician translation (by Condex)
- Change: crossing tunnels is now considered a cheat
- Fix: better AI route finding
- Fix: AI builds less inner-city bus stations
- Fix: Better industry spreading on random maps
- Fix: Two industries that accept the same goods can never be very close to each other
- Feature: Extra dynamite, allow the removal of town-owned roads, bridges, tunnels for a popularity rating penalty
- Feature: magic bulldozer cheat, that lets you remove industries, unmovables and town-owned buildings, roads and bridges
- Fix: destroying bridge (over water or 'higher bridge' with vehicle on it)
- Fix Game crashes when you hit the build rail button
- Fix: some scenarios had a max_railtype of 0
- Fix: Bribe Autorithy. A failed attempt to bribe is now also stored in savegame
- Fix: 80% CPU load paused in fast-forward
- Feature: Enabled 'remove' button for stations
- Feature: Cheat GUI (activate with crtl-alt-c) The game remembers if you have used a cheat
- Fix: Some airport runways were treated
- Fix: minor minimap glitch
- Fix: station sorting scroll fails with not ennough stations
- Fix: desert ground for depots in the desert
- Feature: station sort implemented using qsort()
- Feature: station list shows #of stations owned by player
- Fix: trains could run on wrong track type under bridges
- Fix: screenshot hangs
- Feature: split canal/lock tool in two tools, one for building canals, one for locks.
- Fix: wrong sound with ships
- Fix: toy shop closes even though it has supply
- Fix: nordic characters
- Feature: make the HQ generate passengers and mail
- Fix: slso restore Service Interval when rebuying vehicle
- Fix: crash with map bits > 8
- Fix: ufo crash in busstop
- Fix: town actions has empty row
- Change: made helicopters able to land on small airports again
- Feature: display number of houses in town overview window
- Fix: train stuck with the head in one depot and tail in another
- Fix: Optimized random radio tower spreading
- Feature: Land info now shows type of signal
- Fix: ground below trees is sometimes not covered by snow
- Fix: fast forward button in scenario editor
- Change: screenshots are saved to PERSONAL_DIR (unix)
- Fix: screenshot hotkey does not function in scenario editor
- Fix: allow deleting a bridge if a vehicle is below
- Fix: crash loading a scenario
- Fix: build tracks on water
- Fix: fast forward button pressed with tab
- Fix: vehicles don't get old
- Feature: realistic train reversing
- Feature: added support for 64 bit CPUs
- Fix: finance bug with some original scenarios
- Feature: added water quantity level "very low", which is the default for easy mode now
- Fix: 'Stopped' is shown when train is stopping and 'Reverse' is clicked
- Feature: realistic acceleration turned on, train must first slow down and stop before it can reverse
- Feature: (MorphOS build) various small improvement to make the the game feel more native
- Feature: alt + f now toggles full screen (alt + enter still works)
- Feature: (OSX build) command + q shows the quit window and command + f or enter toggles full screen (alt and control still works too)
- Feature: pasky's autorenew, autorenews vehicles if enabled.
- Feature: (incomplete) news history window
- Feature: larger smallmap size
- Feature: Austrian Citynames
- Feature: repaying most possible debt
- Feature: added Polish translation (by tomek)
- Feature: added Danish translation (by Gof.dk)
- Feature: pasky's grfspecial loader. You have to enable them in openttd.cfg using [newgrf] setting
- Feature: smooth economy changes
- Fix: 100% CPU bug
- Fix: crash when AI builds airport
- Fix: plays wrong music on main screen
- Fix: inflation was way too high when intrest rate = 0
- Fix: can't sell anything if money is TOO negative
- Fix: fast forward button resets
- Feature: TTDPatch-style gotodepot. Ship depots and aircraft hangars can be inserted in the schedule as well.
- Feature: ability to add "service if needed" orders (the "full load" button changes to "service" after selecting a depot order)
- Feature: if a vehicle has depot orders in its schedule, automatic servicing is disabled
- Change: autosaves are now placed in save/autosave
- Feature: patch setting so that helicopters get serviced automatically on helipad
- Fix: "refit train" button remains
- Change: default savegame directory is /save in Linux
- Fix: enable up/down scrolling with the mouse
- Feature: center toolbar on screen
- Feature: sort savelist by date
- Feature: allow scrolling in both directions
- Feature: darkvater's two new airports (metropolitan in 1980 and international in 1990)
- Feature: Resizing the window in all SDL builds
- Fix: 1920 all trains
- Fix: wrong heli breakdownspeed
- Feature: added MIDI flag to makefile to set custom path to midi player
- Fix: station list cargo waiting display bug
- Fix: bug that could allow rails on steep slopes
- Fix: train depots and checkpoints not flooded by water
- Fix: added command line option (-i) to deactivate the grf check
- Fix: signal bug [ 949929 ]
0.3.2.1 (2004-05-23)
- Fix: use english.lng by default
- Fix: No bridges available in 1920
- Fix: czech file was missing
- Feature: now builds on FreeBSD
- Feature: now builds on MorphOS
0.3.2 (2004-05-22)
- Feature: HP for trians limited to 16bit int
- Feature: added Czech translation
- Feature: train refitting
- Feature: auto euro
- Fix: don't allow building railroad stations on airports or bus stations
- Feature: industry directory
- Feature: added extend vehicle life/noexpire patch
- Feature: show revision number in title bar
- Fix: Enable mouse wheel scrolling and zooming in SDL
- Fix: Construct industries producing raw materials
- Fix: loading TTD saves gave incorrect reliability parameters for wagons
- Feature: random network games
- Fix: fixed order restore bug in network play
- Fix: network sync fix for train goto depot
- Feature: smallmap remembers size
- Fix: Only one statue per player per town
- Fix: enhanced patch configurator
- Fix: if realistic acceleration was enabled, train didn't accelerate if they entered a tunnel right after a slope
- Fix: remove sdl frameskip message
- Fix: road vehicle on hills speedfix
- Fix: CompanyValueGraph window too small for currency
- Fix: mkdir() problem in unix.c
- Fix: client kills server if it leaves a networkgame
- Change: autosave go to autosave/
- Fix: Canal tool resets after 1 use
- Feature: remember value of show town names in smallmap
- Feature: norwegian translation
- Feature: norwegian currency
- Feature: slovak language
- Fix: smoother mouse cursor
- Fix: fixed a couple of overlapping memcpys
- Feature: use SO_REUSEADDR on listen socket
- Feature: unix sigabort handling
- Feature: hungarian translation
- Fix: quit to beos
- Fix: dragging to build canals sometimes crashed
- Fix: cactus plants died on desert
- Feature: added norwegian translation
- Feature: added more default resolutions
- Feature: return error message if DOS grf files are used
- Feature: bemidi support
- Fix: invalid letters in spanish town names
- Fix: rail upgrade button
- Fix: makefile reorganization
- Fix: Zoom out button not grayed out
- Fix: no space between some values and units
- Change: Plant area of trees now allowed for 20x20 area
- Change: "kmh^-1" to "km/h"
- Fix: Station catchment outline-tiles weren't shown properly on slopes
- Fix: oil rig station wasn't properly deleted
- Fix: fixed making screenshots in scenario editor
- Feature: added icelandic currency
- Change: show original savegame names for oldstyle savegames
- Fix: mac patches by bjarni
- Fix: fixed alignment issue in station drawing
0.3.1 (2004-04-26)
- Fix: shift+arrows keys scrolls faster (by pasky)
- Feature: bridge pillars for higher bridges
- Fix: [ 941880 ] "monorail in 1985" which allowed you to build monorail/maglev at any year
- Feature: remember cargo payment rates selection, default to all
- Fix: town ratings when companies are deleted/merged
- Fix: vehicle reliability calculation in third phase
- Change: new directory structure (*.grf+sample.cat in data subdir, *.lng in lang subdir)
- Feature: fast forward button
- Fix: random world button in scenario editor doesn't build cities, industries, trees
- Fix: loading worlds with no towns now fails
- Fix: outdated sort order after station renaming
- Feature: copy/share orders from trains in depot
- Fix: better train detection for copy orders
- Fix: [ 938481 ] Euro currency bug
- Fix: [ 938170 ] Go to xxx road depot selection bug (2)
- Fix: [ 934520 ] scrolling and newspaper in title screen
- Feature: swedish translation (by poLiSen)
- Fix: incorrect cargo_days for trains
- Feature: dragging to construct canals
- Fix array bounds error with train breakdown speeds
- Fix: towns deleting random tiles around houses
- Feature: can now have more than 128 towns
- Fix: incorrect road vehicle list caption for competitors
- Fix: vehicle menu graying after a bankrupty
- Feature: always allow building small airports patch
- Feature: colorful newspaper after a certain date
- Feature: build while paused patch
- Feature: polish town names
- Fix: selective road removal
- Feature: clear area now works in scenario editor
- Feature: drag&drop stations
- Fix: make houses available in 1920 to prevent hang
- Fix: duration of breakdown smoke
- Fix: slope bug under bridges
- Feature: more realistic train starting and stopping
- Fix: don't play invalid sounds (fixes road reconstruction crash)
- Fix: display correct train power with multihead engines
- Fix: buffer overflow caused by too long string in english.lng
- Fix: destroying things with no money
0.3.0 (2004-04-14)
- Change: don't slow down trains as much on hills
- Fix: aircraft terminal wasn't properly freed if aircraft crashed
- Fix: fixed station acceptance bug
- Change: limit amount of radiotowers.
- Feature: cost estimation with Shift
- Change: changed speedkey from Shift to Tab.
- Feature: added patch for starting_date, takes a value on the form yyyy, yyyymm or yyyymmdd.
- Feature: support for multiheaded trains
- Feature: sell whole train by dragging loco to special trashcan
- Feature: drag the whole train with ctrl in depot
- Fix: fixed buy shares in company
- Feature: added convert rail tool
- Change: enhanced patches window with pages.
- Feature: patch to select what vehicle types the ai will build
- Feature: better slope graphics
- Fix: only deliver goods to stations that have a rating != 0
- Feature: new pathfinding algorithm for trains (enable with new_pathfinding)
- Change: changed intro graphics
- Change: all player stuff is deleted when you load a scenario.
- Fix: added F hotkeys in scenario editor
- Feature: Added patch to use timidity for BeOS
- Feature: mousewheel can now be used to scroll in windows
- Feature: added coordinate display to landinfo window
- Feature: change default servicing interval for vehicles
- Feature: change max # of vehicles per player
- Fix: unable to raise land next to signal
- Feature: nonuniform stations patch
- Feature: moved error message box out of the way
- Fix: aircraft was shown instead of ships in player overview window
- Feature: canals/shiplifts
- Feature: build tree of random type
- Feature: build trees on area
- Feature: added color coded vehicle profits
- Feature: ability to close error messages with space.
- Fix: updated installer to take care of savegames more carefully
- Fix: don't make a new subsidy if there already exists one that is currently active by a company
- Fix: town directory sometimes showed huge numbers
- Fix: fixed bugs when changing owners of items (pieces of rail were not always deleted),
- Feature: network games (currently unsupported)
- Fix: fixed bug with large stations in train pathfinder
- Change: use save/ as save folder on win32
- Feature: bigger demolish tool
- Change: moved date in news window
- Feature: two more bridges
- Feature: improved depot finding
- Feature: bribe the town authority
- Feature: allow building many trees on a single tile.
- Feature: added snow_line_height setting, only affects new games.
- Change: don't check if tiles around the clicked station is a station in order gui
- Fix: deleting docks doesn't produce land
- Fix: deleting ship depot doesn't produce land
- Fix: buoy is now treated as water when flooding
- Feature: errmsg_duration controls how long error messages are displayed
- Fix: combo presignals bug fix
- Fix: prevent going to 0,0 if airport/docks is deleted
- Feature: fullscreen_bpp setting in [win32] sets the bpp to use in fullscreen mode
- Fix: french town names had bad letters in them
- Feature: euro symbol
- Feature: high bridges
- Fix: order list when replacing train didn't work properly
- Change: keep checkpoint button down after placing
- Fix: start in the middle of the map
- Change: moved disk devices to bottom of list on win32
- Fix: more error tolerant saveload code
- Feature: ZLIB savegames (smaller than before)
- Feature: PNG,PCX screenshot support
- Feature: indicate with gray in vehicle popup menus if company has no vehicles of that type
- Feature: clicking on the money brings up finances
- Fix: (OSX build) now runs even if sdl is not present on the system
- Fix: (OSX build) now runs on systems older than 10.3
- Fix: (OSX build) altered compiler settings to make a completely stable app
- Feature: (OSX build) distribution now uses Apples package system for easier updates
- Feature: (OSX build) Application is now a proper bundle application
0.2.1 (2004-04-04)
- Fix: copy orders crashed if you clicked on a wagon
- Feature: 'A' hotkey now always opens autorail
- Change: Moved autorail button
- Feature: X can be used to toggle transparent buildings
- Fix: don't show transparent buildings in intro
- Fix: installer doesn't delete savegames
- Feature: Hotkeys 1-9 can be used to build a bridge in the bridge window
- Feature: Added more hotkeys in the road build window
0.2 (2004-04-03)
- Feature: autoscroll (only works to left/right)
- Feature: train checkpoints, instead of ttdpatch's nonstop handling
- Feature: ttdpatch compatible nonstop handling
- Fix: news window was moved strangely when resizing
- Fix: fixed sign drawing bug in max zoom out mode
- Feature: refresh rate configuration setting
- Feature: town directory sorting options
- Feature: pre-signals (ctrl-click on existing signals to change signal type)
- Feature: show semaphores on the right side if right-sided traffic
- Improvement: increased number of windows on screen to 20
- Feature: patch options configuration window
- Fix: road vehicles sometimes getting stuck
- Feature: autorail build tool
- Feature: "show yearly finances window" option
- Feature: "signals on drive side" patch (by Michael Polnick)
- Fix: connecting tracks behind depot causing incorrect signal behavior
- Fix: save/load diskspace bug
- Feature: "show full date in statusbar" option
- Feature: italian translation (by duepixel)
- Feature: road and rail removal by dragging a selection
- Feature: news item for "train is unprofitable"
- Feature: news item for "train is lost"
- Feature: (win32 build) double size mode (ctrl-d to toggle)
- Fix: incorrect bridge cost for long bridges
- Feature: "multiple similar industries in close proximity" option
- Feature: "multiple industries per down" option
- Feature: "crossing tunnels" option
- Feature: order sharing and copying ("goto" on other vehicle to copy, ctrl+"goto" to share)
- Feature: remember last built rail type
- Feature: "debtmax" faster loan management with ctrl key
- Fix: disallow buoy in north corner
- Feature: "go to depot" orders option
- Feature: "long bridges" option
- Feature: "select goods" option
- Feature: "no train service" option
- Feature: "no inflation" option
- Improvement: (OSX build) now starts when doubleclicked
- Improvement: (OSX build) significant performance increase
- Improvement: optimized startup time
- Feature: automatically detect available resolutions
- Feature: "full load any" option, as in ttdpatch
- Feature: automatic detection of available language files
- Feature: German translation (by truesatan and wuntvor)
- Improvement: sorted savegame list
- Feature: finnish town names (by Jpl)
- Feature: remember custom difficulty settings
- Fix: shift key now increases game speed only when game window is active
- Fix: ctrl button now works with SDL driver
- Feature: configuration file system
- Feature: show vehicle speed in vehicle view windows
- Fix: incorrect weight displayed in "new trains" window
- Feature: train depot window now has horizontal scrollbar
- Feature: mammoth trains
- Fix: incorrect train running cost in newspaper
- Feature: on-the-fly language selection
- Feature: load old premade ttd maps (must be renamed to .sv1 extension)
0.1.4
- Feature: crash submit system on win32
- Fix: train smoke clouds
- Fix: train engine sounds
- Fix: play all sounds at 11025 hz (fixes certain sounds)
- Feature: autosave
- Fix: scenario editor desert button now makes desert instead of lighthouse
- Fix: creating random town in scenario editor crash
- Fix: candy bubbles sometimes caused crash
- Fix: wrong speed was shown in news window for some vehicles
- Fix: graph color bleeding
- Feature: build on coasts
- Feature: Allow building transmitters, lighthouses and company headquarters on slopes
- Feature: now builds on MacOSX
- Fix: arrow keys with SDL driver
- Change: new savegame format
- Change: new format for english.lng
- Fix: don't allow trains to road depots
- Fix: road vehicle was sometimes shown inside depot
- Fix: arrow keys in sdl driver were wrong
- Fix: endianness bugs in save/load
- Fix: now builds on FreeBSD
- Fix: screenshot feature now works
- Fix: rail foundations sometimes displayed unnecessarily
- Fix: minor AI bugs
- Fix: fixed industry sounds
- Feature: in-game resolution selection via settings window
- Feature: Dutch town names
- Feature: Added load game menu item
- Fix: bug where ship depots were very expensive
- Fix: BeOS build (by MYOB)
- Fix: yearly expenses data being the same for the past two game years
- Fix: adding songs to playlists other than custom1 and custom2
- Fix: first and last tracks playing the wrong music
- Fix: Palette animation for SDL video (rob)
- Fix: Get remaining disk space on most Unix-en (rob)
- Fix: screen went black when resizing
0.1.3
- Fixed message options window
- Fixed company takeover/purchase
- Feature: Improved mouse scroll zooming
- Fixed station code so it's not possible to steal another player's temporarily deleted station
- Fixed subsidy owner bug when deleting station
- Fixed crash when deleting a bridge with a train on it
- Feature: Larger stations and possibility to join stations
- Fixed missing candy initial cargo payment values
- Fixed Goods and Food/FizzyDrinks subsidies
- Fixed graphical glitch in subsidies window
- Take over company dialog was not shown properly
- Fixed crash if player windows were open while the company went bankrupt
- Fixed train slowness on hills
- Feature: swedish town names (patch by glottis)
- Feature: more currencies
- Better window resizing/zooming
- Added goto road vehicle depot for road vehicle orders
- Possibility to use either semaphores or signals (Ctrl key)
- Limited the scrolling rate for year selector in scenario editor
0.1.2
- Mouse wheel can be used to zoom in out on win32 (ludde)
- Implemented some support for resizing the window dynamically in win32 (ludde)
- Fixed tunnel mouse icon for maglev and monorail
0.1.1
- Preliminary presignal support
- Added external MIDI driver for unix version (by robertnorris)
- Added DirectMusic driver for Win32 version
- Fixed problem where directories weren't displayed under Linux (by Markus)
- Center windows properly in higher resolutions
- Added "build tracks on slopes" feature
- Fixed colors in map window for routes
- Command line -g flag now optionally takes a game to load
- Fixed road drive side
- Fixed "Fund road construction" not clickable when unavailable

@ -0,0 +1,806 @@
#include "stdafx.h"
#include "ttd.h"
#include "viewport.h"
#include "command.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 ((GET_TILE_X(tile) == TILE_X_MAX) || (GET_TILE_Y(tile) == TILE_Y_MAX))
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 _map_type_and_height[tile] & 0xF;
}
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+TILE_XY(0,-1));
TerraformAddDirtyTile(ts, tile+TILE_XY(-1,-1));
TerraformAddDirtyTile(ts, tile+TILE_XY(-1,0));
TerraformAddDirtyTile(ts, tile);
}
static int TerraformProc(TerraformerState *ts, uint tile, int mode)
{
int r;
int32 ret;
assert(tile < TILES_X * TILES_Y);
if ((r=TerraformAllowTileProcess(ts, tile)) <= 0)
return r;
if ((_map_type_and_height[tile] >> 4) == MP_RAILWAY) {
static const byte _railway_modes[4] = {8, 0x10, 4, 0x20};
static const byte _railway_dangslopes[4] = {0xd, 0xe, 7, 0xb};
// Nothing could be built at the steep slope - this avoids a bug
// when you have a single diagonal track in one corner on a
// basement and then you raise the other corner.
if ((GetTileSlope(tile, NULL)&0xF) == _railway_dangslopes[mode]) {
_error_message = STR_1008_MUST_REMOVE_RAILROAD_TRACK;
return -1;
}
// If we have a single diagonal track there, the other side of
// tile can be terraformed.
if ((_map5[tile]&~0x40) == _railway_modes[mode])
return 0;
}
ret = DoCommandByTile(tile, 0,0, ts->flags & ~DC_EXEC, CMD_LANDSCAPE_CLEAR);
if (ret == CMD_ERROR) {
_terraform_err_tile = tile;
return -1;
}
ts->cost += ret;
if (ts->tile_table_count >= 625)
return -1;
ts->tile_table[ts->tile_table_count++] = tile;
return 0;
}
static bool TerraformTileHeight(TerraformerState *ts, uint tile, int height)
{
int nh;
TerraformerHeightMod *mod;
int count;
assert(tile < TILES_X * TILES_Y);
if (height < 0) {
_error_message = STR_1003_ALREADY_AT_SEA_LEVEL;
return false;
}
_error_message = STR_1004_TOO_HIGH;
if (height > 0xF)
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 + TILE_XY(0,-1), 1)<0)
return false;
if (TerraformProc(ts, tile + TILE_XY(-1,-1), 2)<0)
return false;
if (TerraformProc(ts, tile + TILE_XY(-1,0), 3)<0)
return false;
mod = ts->modheight;
count = ts->modheight_count;
for(;;) {
if (count == 0) {
if (ts->modheight_count >= 576)
return false;
ts->modheight_count++;
break;
}
if (mod->tile == (TileIndex)tile)
break;
mod++;
count--;
}
mod->tile = (TileIndex)tile;
mod->height = (byte)height;
ts->cost += _price.terraform;
{
int direction = ts->direction, r;
const TileIndexDiff *ttm;
static const TileIndexDiff _terraform_tilepos[5] = {TILE_XY(1,0), TILE_XY(-2,0), TILE_XY(1,1), TILE_XY(0,-2), 0 };
for(ttm = _terraform_tilepos; *ttm != 0; ttm++) {
tile += *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
* p1 - corners
* p2 - direction
*/
int32 CmdTerraformLand(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
TerraformerState ts;
uint 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 = TILE_FROM_XY(x,y);
if (p1 & 1) {
if (!TerraformTileHeight(&ts, tile+TILE_XY(1,0),
(_map_type_and_height[tile+TILE_XY(1,0)]&0xF) + direction))
return CMD_ERROR;
}
if (p1 & 2) {
if (!TerraformTileHeight(&ts, tile+TILE_XY(1,1),
(_map_type_and_height[tile+TILE_XY(1,1)]&0xF) + direction))
return CMD_ERROR;
}
if (p1 & 4) {
if (!TerraformTileHeight(&ts, tile+TILE_XY(0,1),
(_map_type_and_height[tile+TILE_XY(0,1)]&0xF) + direction))
return CMD_ERROR;
}
if (p1 & 8) {
if (!TerraformTileHeight(&ts, tile+TILE_XY(0,0),
(_map_type_and_height[tile+TILE_XY(0,0)]&0xF) + direction))
return CMD_ERROR;
}
if (direction == -1) {
/* Check if tunnel would take damage */
int count;
TileIndex *ti = ts.tile_table;
for(count = ts.tile_table_count; count != 0; count--, ti++) {
uint z, t;
uint tile = *ti;
z = TerraformGetHeightOfTile(&ts, tile + TILE_XY(0,0));
t = TerraformGetHeightOfTile(&ts, tile + TILE_XY(1,0));
if (t <= z) z = t;
t = TerraformGetHeightOfTile(&ts, tile + TILE_XY(1,1));
if (t <= z) z = t;
t = TerraformGetHeightOfTile(&ts, tile + TILE_XY(0,1));
if (t <= z) z = t;
if (!CheckTunnelInWay(tile, z*8))
return_cmd_error(STR_1002_EXCAVATION_WOULD_DAMAGE);
}
}
if (flags & DC_EXEC) {
/* Clear the landscape at the tiles */
{
int count;
TileIndex *ti = ts.tile_table;
for(count = ts.tile_table_count; count != 0; count--, ti++) {
DoCommandByTile(*ti, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
}
}
/* change the height */
{
int count;
TerraformerHeightMod *mod;
uint til;
mod = ts.modheight;
for(count = ts.modheight_count; count != 0; count--, mod++) {
til = mod->tile;
// Change tile height
_map_type_and_height[til] = (_map_type_and_height[til]&~0x0F)|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;
}
/*
* p1 - start
*/
int32 CmdLevelLand(int ex, int ey, uint32 flags, uint32 p1, uint32 p2)
{
int size_x, size_y;
int sx, sy;
uint h, curh;
uint tile;
int32 ret, cost, money;
// remember level height
h = _map_type_and_height[p1]&0xF;
ex >>= 4; ey >>= 4;
// make sure sx,sy are smaller than ex,ey
sx = GET_TILE_X(p1);
sy = GET_TILE_Y(p1);
if (ex < sx) intswap(ex, sx);
if (ey < sy) intswap(ey, sy);
tile = TILE_XY(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 = _map_type_and_height[tile2]&0xF;
while (curh != h) {
ret = DoCommandByTile(tile2, 8, (curh > h)?0:1, flags & ~DC_EXEC, CMD_TERRAFORM_LAND);
if (ret == CMD_ERROR) 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)
if (cost == 0) return CMD_ERROR;
return cost;
}
/* Purchase a land area
* p1 = unused
* p2 = unused
*/
int32 CmdPurchaseLandArea(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
uint tile;
int32 cost;
SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
tile = TILE_FROM_XY(x,y);
if (!EnsureNoVehicle(tile))
return CMD_ERROR;
if (IS_TILETYPE(tile, MP_UNMOVABLE) &&
_map5[tile] == 3 &&
_map_owner[tile] == _current_player)
return_cmd_error(STR_5807_YOU_ALREADY_OWN_IT);
cost = DoCommandByTile(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
if (cost == CMD_ERROR)
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;
}
int32 ClearTile_Clear(uint tile, byte flags) {
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[_map5[tile] & 0x1F];
if (flags & DC_EXEC)
DoClearSquare(tile);
if (price == NULL)
return 0;
return *price;
}
int32 CmdSellLandArea(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
uint tile;
SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
tile = TILE_FROM_XY(x,y);
if (!CheckTileOwnership(tile))
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(TileInfo *ti, byte set)
{
DrawGroundSprite(0xF54 + _tileh_to_sprite[ti->tileh] + set * 19);
}
void DrawHillyLandTile(TileInfo *ti)
{
if (ti->tileh != 0) {
DrawGroundSprite(0xFA0 + _tileh_to_sprite[ti->tileh]);
} else {
DrawGroundSprite(_landscape_clear_sprites[((ti->x^ti->y) >> 4) & 0x7]);
}
}
void DrawClearLandFence(TileInfo *ti, byte img)
{
byte z = ti->z;
if (ti->tileh & 2) {
z += 8;
if (ti->tileh == 0x17)
z += 8;
}
if (img & 0x38) {
DrawGroundSpriteAt(_clear_land_fence_sprites_1[((img >> 3) & 7) - 1] + _fence_mod_by_tileh[ti->tileh], ti->x, ti->y, z);
}
if (img & 0x7) {
DrawGroundSpriteAt(_clear_land_fence_sprites_1[(img & 7) - 1] + _fence_mod_by_tileh_2[ti->tileh], ti->x, ti->y, z);
}
}
static void DrawTile_Clear(TileInfo *ti)
{
switch((ti->map5 & (7<<2)) >> 2) {
case 0:
DrawClearLandTile(ti, (ti->map5 & 3));
break;
case 1:
DrawHillyLandTile(ti);
break;
case 2:
DrawGroundSprite(0xFB7 + _tileh_to_sprite[ti->tileh]);
break;
case 3:
DrawGroundSprite( _clear_land_sprites_1[_map3_lo[ti->tile]&0xF] + _tileh_to_sprite[ti->tileh]);
break;
case 4:
DrawGroundSprite( _clear_land_sprites_2[ti->map5&3] + _tileh_to_sprite[ti->tileh]);
break;
case 5:
DrawGroundSprite( _clear_land_sprites_3[ti->map5&3] + _tileh_to_sprite[ti->tileh]);
break;
}
DrawClearLandFence(ti, _map3_hi[ti->tile] >> 2);
}
uint GetSlopeZ_Clear(TileInfo *ti) { return GetPartialZ(ti->x&0xF, ti->y&0xF, ti->tileh) + ti->z; }
static void GetAcceptedCargo_Clear(uint tile, AcceptedCargo *ac)
{
/* unused */
}
static void AnimateTile_Clear(uint tile)
{
/* unused */
}
void TileLoopClearHelper(uint tile)
{
byte img_1, img_2;
static byte img_by_map5[8] = { 0,0,0,2, 1,1,0,0, };
uint dirty = -1;
img_1 = 0;
if (IS_TILETYPE(tile, MP_CLEAR)) {
img_1 = img_by_map5[(_map5[tile] & 0x1C) >> 2];
} else if (IS_TILETYPE(tile, MP_TREES) && (_map2[tile] & 0x30) == 0x20) {
img_1 = 1;
}
img_2 = 0;
if (IS_TILETYPE(TILE_ADDXY(tile, 1, 0), MP_CLEAR)) {
img_2 = img_by_map5[(_map5[TILE_ADDXY(tile, 1, 0)] & 0x1C) >> 2];
} else if (IS_TILETYPE(TILE_ADDXY(tile, 1, 0), MP_TREES) && (_map2[TILE_ADDXY(tile, 1, 0)] & 0x30) == 0x20) {
img_2 = 1;
}
if (!(_map3_hi[tile] & 0xE0)) {
if ( (img_1&2) != (img_2&2) ) {
_map3_hi[tile] |= 3 << 5;
dirty = tile;
}
} else {
if (img_1 == 1 && img_2 == 1) {
_map3_hi[tile] &= ~(3 << 5);
dirty = tile;
}
}
img_2 = 0;
if (IS_TILETYPE(TILE_ADDXY(tile, 0, 1), MP_CLEAR)) {
img_2 = img_by_map5[(_map5[TILE_ADDXY(tile, 0, 1)] & 0x1C) >> 2];
} else if (IS_TILETYPE(TILE_ADDXY(tile, 0, 1), MP_TREES) && (_map2[TILE_ADDXY(tile, 0, 1)] & 0x30) == 0x20) {
img_2 = 1;
}
if (!(_map3_hi[tile] & 0x1C)) {
if ( (img_1&2) != (img_2&2) ) {
_map3_hi[tile] |= 3 << 2;
dirty = tile;
}
} else {
if (img_1 == 1 && img_2 == 1) {
_map3_hi[tile] &= ~(3 << 2);
dirty = tile;
}
}
if (dirty != -1)
MarkTileDirtyByTile(dirty);
}
/* convert into snowy tiles */
static void TileLoopClearAlps(uint tile)
{
int k;
byte m5,tmp;
/* distance from snow line, in steps of 8 */
k = GetTileZ(tile) - _opt.snow_line;
m5 = _map5[tile] & 0x1C;
tmp = _map5[tile] & 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;
}
_map5[tile] = m5;
MarkTileDirtyByTile(tile);
}
static void TileLoopClearDesert(uint tile)
{
if ( (_map5[tile] & 0x1C) == 0x14)
return;
if (GetMapExtraBits(tile) == 1) {
_map5[tile] = 0x17;
} else {
if (GetMapExtraBits(tile+TILE_XY(1,0)) != 1 &&
GetMapExtraBits(tile+TILE_XY(-1,0)) != 1 &&
GetMapExtraBits(tile+TILE_XY(0,1)) != 1 &&
GetMapExtraBits(tile+TILE_XY(0,-1)) != 1)
return;
_map5[tile] = 0x15;
}
MarkTileDirtyByTile(tile);
}
static void TileLoop_Clear(uint tile)
{
byte m5,m3;
TileLoopClearHelper(tile);
if (_opt.landscape == LT_DESERT) {
TileLoopClearDesert(tile);
} else if (_opt.landscape == LT_HILLY) {
TileLoopClearAlps(tile);
}
m5 = _map5[tile];
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
_map5[tile] = m5;
return;
}
/* did overflow, so continue */
} else {
m5 = ((byte)Random() > 21) ? (2) : (6);
}
m5++;
} else if (_game_mode != GM_EDITOR) {
/* handle farm field */
m5 += 0x20;
if (m5 >= 0x20) {
// Didn't overflow
_map5[tile] = m5;
return;
}
/* overflowed */
m3 = _map3_lo[tile] + 1;
assert( (m3 & 0xF) != 0);
if ( (m3 & 0xF) >= 9) /* NOTE: will not work properly if m3&0xF == 0xF */
m3 &= ~0xF;
_map3_lo[tile] = m3;
}
_map5[tile] = m5;
MarkTileDirtyByTile(tile);
}
void GenerateClearTile()
{
int i,j;
uint tile,tile_new;
uint32 r;
/* add hills */
i = (Random() & 0x3FF) | 0x400;
do {
tile = TILE_MASK(Random());
if (IS_TILETYPE(tile, MP_CLEAR))
_map5[tile] = (byte)((_map5[tile] & ~(3<<2)) | (1<<2));
} while (--i);
/* add grey squares */
i = (Random() & 0x7F) | 0x80;
do {
r = Random();
tile = TILE_MASK(r);
if (IS_TILETYPE(tile, MP_CLEAR)) {
j = ((r >> 16) & 0xF) + 5;
for(;;) {
_map5[tile] = (byte)((_map5[tile] & ~(3<<2)) | (2<<2));
do {
if (--j == 0) goto get_out;
tile_new = tile + _tileoffs_by_dir[Random() & 3];
} while (!IS_TILETYPE(tile_new, MP_CLEAR));
tile = tile_new;
}
get_out:;
}
} while (--i);
}
static void ClickTile_Clear(uint tile)
{
/* not used */
}
uint32 GetTileTrackStatus_Clear(uint tile, int mode)
{
return 0;
}
static const StringID _clear_land_str[4+8-1] = {
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(uint tile, TileDesc *td)
{
int i = (_map5[tile]>>2) & 7;
if (i == 0)
i = (_map5[tile] & 3) + 8;
td->str = _clear_land_str[i - 1];
td->owner = _map_owner[tile];
}
static void ChangeTileOwner_Clear(uint tile, byte old_player, byte new_player)
{
return;
}
void InitializeClearLand() {
_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 */
};

@ -0,0 +1,493 @@
#include "stdafx.h"
#include "ttd.h"
#include "gui.h"
#include "command.h"
#include "player.h"
#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(CmdBuildSignals);
DEF_COMMAND(CmdRemoveSignals);
DEF_COMMAND(CmdTerraformLand);
DEF_COMMAND(CmdPurchaseLandArea);
DEF_COMMAND(CmdSellLandArea);
DEF_COMMAND(CmdBuildTunnel);
DEF_COMMAND(CmdBuildTrainDepot);
DEF_COMMAND(CmdBuildTrainCheckpoint);
DEF_COMMAND(CmdRenameCheckpoint);
DEF_COMMAND(CmdRemoveTrainCheckpoint);
DEF_COMMAND(CmdBuildTruckStation);
DEF_COMMAND(CmdBuildBusStation);
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(CmdTrainGotoDepot);
DEF_COMMAND(CmdForceTrainProceed);
DEF_COMMAND(CmdReverseTrainDirection);
DEF_COMMAND(CmdModifyOrder);
DEF_COMMAND(CmdSkipOrder);
DEF_COMMAND(CmdDeleteOrder);
DEF_COMMAND(CmdInsertOrder);
DEF_COMMAND(CmdChangeTrainServiceInt);
DEF_COMMAND(CmdRestoreOrderIndex);
DEF_COMMAND(CmdBuildIndustry);
//DEF_COMMAND(CmdDestroyIndustry);
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(CmdChangeAircraftServiceInt);
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(CmdChangeRoadVehServiceInt);
DEF_COMMAND(CmdPause);
DEF_COMMAND(CmdResume);
DEF_COMMAND(CmdBuyShareInCompany);
DEF_COMMAND(CmdSellShareInCompany);
DEF_COMMAND(CmdBuyCompany);
DEF_COMMAND(CmdBuildTown);
DEF_COMMAND(CmdRenameTown);
DEF_COMMAND(CmdDoTownAction);
DEF_COMMAND(CmdSetRoadDriveSide);
DEF_COMMAND(CmdSetTownNameType);
DEF_COMMAND(CmdChangeDifficultyLevel);
DEF_COMMAND(CmdStartStopShip);
DEF_COMMAND(CmdSellShip);
DEF_COMMAND(CmdBuildShip);
DEF_COMMAND(CmdSendShipToDepot);
DEF_COMMAND(CmdChangeShipServiceInt);
DEF_COMMAND(CmdRefitShip);
DEF_COMMAND(CmdStartNewGame);
DEF_COMMAND(CmdLoadGame);
DEF_COMMAND(CmdCreateScenario);
DEF_COMMAND(CmdSetSinglePlayer);
DEF_COMMAND(CmdSetNewLandscapeType);
DEF_COMMAND(CmdGenRandomNewGame);
DEF_COMMAND(CmdCloneOrder);
DEF_COMMAND(CmdClearArea);
DEF_COMMAND(CmdMoneyCheat);
DEF_COMMAND(CmdBuildCanal);
DEF_COMMAND(CmdPlayerCtrl);
DEF_COMMAND(CmdLevelLand);
DEF_COMMAND(CmdRefitRailVehicle);
DEF_COMMAND(CmdBuildLock);
DEF_COMMAND(CmdStartScenario);
/* The master command table */
static CommandProc * const _command_proc_table[] = {
CmdBuildRailroadTrack, /* 0 */
CmdRemoveRailroadTrack, /* 1 */
CmdBuildSingleRail, /* 2 */
CmdRemoveSingleRail, /* 3 */
CmdLandscapeClear, /* 4 */
CmdBuildBridge, /* 5 */
CmdBuildRailroadStation, /* 6 */
CmdBuildTrainDepot, /* 7 */
CmdBuildSignals, /* 8 */
CmdRemoveSignals, /* 9 */
CmdTerraformLand, /* 10 */
CmdPurchaseLandArea, /* 11 */
CmdSellLandArea, /* 12 */
CmdBuildTunnel, /* 13 */
CmdRemoveFromRailroadStation, /* 14 */
CmdConvertRail, /* 15 */
CmdBuildTrainCheckpoint, /* 16 */
CmdRenameCheckpoint, /* 17 */
CmdRemoveTrainCheckpoint, /* 18 */
CmdBuildTruckStation, /* 19 */
NULL, /* 20 */
CmdBuildBusStation, /* 21 */
NULL, /* 22 */
CmdBuildLongRoad, /* 23 */
CmdRemoveLongRoad, /* 24 */
CmdBuildRoad, /* 25 */
CmdRemoveRoad, /* 26 */
CmdBuildRoadDepot, /* 27 */
NULL, /* 28 */
CmdBuildAirport, /* 29 */
CmdBuildDock, /* 30 */
CmdBuildShipDepot, /* 31 */
CmdBuildBuoy, /* 32 */
CmdPlantTree, /* 33 */
CmdBuildRailVehicle, /* 34 */
CmdMoveRailVehicle, /* 35 */
CmdStartStopTrain, /* 36 */
NULL, /* 37 */
CmdSellRailWagon, /* 38 */
CmdTrainGotoDepot, /* 39 */
CmdForceTrainProceed, /* 40 */
CmdReverseTrainDirection, /* 41 */
CmdModifyOrder, /* 42 */
CmdSkipOrder, /* 43 */
CmdDeleteOrder, /* 44 */
CmdInsertOrder, /* 45 */
CmdChangeTrainServiceInt, /* 46 */
CmdBuildIndustry, /* 47 */
CmdBuildCompanyHQ, /* 48 */
CmdSetPlayerFace, /* 49 */
CmdSetPlayerColor, /* 50 */
CmdIncreaseLoan, /* 51 */
CmdDecreaseLoan, /* 52 */
CmdWantEnginePreview, /* 53 */
CmdNameVehicle, /* 54 */
CmdRenameEngine, /* 55 */
CmdChangeCompanyName, /* 56 */
CmdChangePresidentName, /* 57 */
CmdRenameStation, /* 58 */
CmdSellAircraft, /* 59 */
CmdStartStopAircraft, /* 60 */
CmdBuildAircraft, /* 61 */
CmdSendAircraftToHangar, /* 62 */
CmdChangeAircraftServiceInt, /* 63 */
CmdRefitAircraft, /* 64 */
CmdPlaceSign, /* 65 */
CmdRenameSign, /* 66 */
CmdBuildRoadVeh, /* 67 */
CmdStartStopRoadVeh, /* 68 */
CmdSellRoadVeh, /* 69 */
CmdSendRoadVehToDepot, /* 70 */
CmdTurnRoadVeh, /* 71 */
CmdChangeRoadVehServiceInt, /* 72 */
CmdPause, /* 73 */
CmdBuyShareInCompany, /* 74 */
CmdSellShareInCompany, /* 75 */
CmdBuyCompany, /* 76 */
CmdBuildTown, /* 77 */
NULL, /* 78 */
NULL, /* 79 */
CmdRenameTown, /* 80 */
CmdDoTownAction, /* 81 */
CmdSetRoadDriveSide, /* 82 */
CmdSetTownNameType, /* 83 */
NULL, /* 84 */
CmdChangeDifficultyLevel, /* 85 */
CmdStartStopShip, /* 86 */
CmdSellShip, /* 87 */
CmdBuildShip, /* 88 */
CmdSendShipToDepot, /* 89 */
CmdChangeShipServiceInt, /* 90 */
CmdRefitShip, /* 91 */
CmdStartNewGame, /* 92 */
CmdLoadGame, /* 93 */
CmdCreateScenario, /* 94 */
CmdSetSinglePlayer, /* 95 */
NULL, /* 96 */
CmdSetNewLandscapeType, /* 97 */
CmdGenRandomNewGame, /* 98 */
CmdCloneOrder, /* 99 */
CmdClearArea, /* 100 */
CmdResume, /* 101 */
CmdMoneyCheat, /* 102 */
CmdBuildCanal, /* 103 */
CmdPlayerCtrl, /* 104 */
CmdLevelLand, /* 105 */
CmdRefitRailVehicle, /* 106 */
CmdRestoreOrderIndex, /* 107 */
CmdBuildLock, /* 108 */
CmdStartScenario /* 109 */
//CmdDestroyIndustry, /* 109 */
};
int32 DoCommandByTile(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc)
{
return DoCommand(GET_TILE_X(tile)*16, GET_TILE_Y(tile)*16, p1, p2, flags, procc);
}
//extern void _stdcall Sleep(int s);
int32 DoCommand(int x, int y, uint32 p1, uint32 p2, uint32 flags, uint procc)
{
int32 res;
CommandProc *proc;
proc = _command_proc_table[procc];
if (_docommand_recursive == 0) {
_error_message = INVALID_STRING_ID;
// update last build coord of player
if ( (x|y) != 0 && _current_player < MAX_PLAYERS) {
DEREF_PLAYER(_current_player)->last_build_coordinate = TILE_FROM_XY(x,y);
}
}
_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 ((uint32)res >> 16 == 0x8000) {
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--;
return res;
}
}
// execute the command here.
_yearly_expenses_type = 0;
res = proc(x, y, flags, p1, p2);
if ((uint32)res >> 16 == 0x8000) {
if (res & 0xFFFF) _error_message = res & 0xFFFF;
error:
_docommand_recursive--;
return CMD_ERROR;
}
// if toplevel, subtract the money.
if (--_docommand_recursive == 0) {
SubtractMoneyFromPlayer(res);
}
return res;
}
int32 GetAvailableMoneyForCommand()
{
uint pid = _current_player;
if (pid >= 8) return 0x7FFFFFFF; // max int
return DEREF_PLAYER(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 = GET_TILE_X(tile)*16;
int y = GET_TILE_Y(tile)*16;
assert(_docommand_recursive == 0);
_error_message = INVALID_STRING_ID;
_error_message_2 = cmd >> 16;
_additional_cash_required = 0;
// spectator has no rights.
if (_current_player == 0xff) {
ShowErrorMessage(_error_message, _error_message_2, x, y);
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];
// this command is a notest command?
notest =
(cmd & 0xFF) == CMD_CLEAR_AREA ||
(cmd & 0xFF) == CMD_CONVERT_RAIL ||
(cmd & 0xFF) == CMD_LEVEL_LAND ||
(cmd & 0xFF) == CMD_TRAIN_GOTO_DEPOT;
if (_networking && (cmd & CMD_ASYNC)) notest = true;
_docommand_recursive = 1;
// cost estimation only?
if (_shift_pressed && _current_player == _local_player && !(cmd & CMD_DONT_NETWORK)) {
// estimate the cost.
res = proc(x, y, flags, p1, p2);
if ((uint32)res >> 16 == 0x8000) {
if (res & 0xFFFF) _error_message = res & 0xFFFF;
ShowErrorMessage(_error_message, _error_message_2, x, y);
} else {
ShowEstimatedCostOrIncome(res, x, y);
}
_docommand_recursive = 0;
return false;
}
// unless the command is a notest command, check if it can be executed.
if (!notest) {
// first test if the command can be executed.
res = proc(x,y, flags, p1, p2);
if ((uint32)res >> 16 == 0x8000) {
if (res & 0xFFFF) _error_message = res & 0xFFFF;
goto show_error;
}
// no money?
if (res != 0 && !CheckPlayerHasMoney(res)) goto show_error;
}
// put the command in a network queue and execute it later?
if (_networking && !(cmd & CMD_DONT_NETWORK)) {
NetworkSendCommand(tile, p1, p2, cmd, callback);
_docommand_recursive = 0;
return true;
}
// update last build coordinate of player.
if ( tile != 0 && _current_player < MAX_PLAYERS) DEREF_PLAYER(_current_player)->last_build_coordinate = tile;
// actually try and execute the command.
_yearly_expenses_type = 0;
res2 = proc(x,y, flags|DC_EXEC, p1, p2);
if (!notest) {
assert(res == res2); // sanity check
} else {
if ((uint32)res2 >> 16 == 0x8000) {
if (res2 & 0xFFFF) _error_message = res2 & 0xFFFF;
goto show_error;
}
}
SubtractMoneyFromPlayer(res2);
if (_current_player == _local_player && _game_mode != GM_EDITOR) {
if (res2 != 0)
ShowCostOrIncomeAnimation(x, y, GetSlopeZ(x, y), res2);
if (_additional_cash_required) {
SET_DPARAM32(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);
return true;
show_error:
// show error message if the command fails?
if (_current_player == _local_player && _error_message_2 != 0)
ShowErrorMessage(_error_message, _error_message_2, x,y);
callb_err:
_docommand_recursive = 0;
if (callback) callback(false, tile, p1, p2);
return false;
}

@ -0,0 +1,180 @@
#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_CHECKPOINT = 16,
CMD_RENAME_CHECKPOINT = 17,
CMD_REMOVE_TRAIN_CHECKPOINT = 18,
CMD_BUILD_TRUCK_STATION = 19,
CMD_BUILD_BUS_STATION = 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_TRAIN_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_CHANGE_AIRCRAFT_SERVICE_INT = 63,
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_CHANGE_ROADVEH_SERVICE_INT = 72,
CMD_PAUSE = 73,
CMD_BUY_SHARE_IN_COMPANY = 74,
CMD_SELL_SHARE_IN_COMPANY = 75,
CMD_BUY_COMPANY = 76,
CMD_BUILD_TOWN = 77,
CMD_RENAME_TOWN = 80,
CMD_DO_TOWN_ACTION = 81,
CMD_SET_ROAD_DRIVE_SIDE = 82,
CMD_SET_TOWN_NAME_TYPE = 83,
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_CHANGE_SHIP_SERVICE_INT = 90,
CMD_REFIT_SHIP = 91,
CMD_START_NEW_GAME = 92,
CMD_LOAD_GAME = 93,
CMD_CREATE_SCENARIO = 94,
CMD_SET_SINGLE_PLAYER = 95,
CMD_SET_NEW_LANDSCAPE_TYPE = 97,
CMD_GEN_RANDOM_NEW_GAME = 98,
CMD_CLONE_ORDER = 99,
CMD_CLEAR_AREA = 100,
CMD_RESUME = 101,
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_START_SCENARIO = 109,
//CMD_DESTROY_INDUSTRY = 109,
};
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_DONT_NETWORK = 0x800, // execute the command without sending it on the network
CMD_ASYNC = 0x1000, // execute the command asynchronously without testing first in networking
};
//#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)
/* 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);
int32 GetAvailableMoneyForCommand();
#endif /* COMMAND_H */

24
configure vendored

@ -0,0 +1,24 @@
#!/bin/sh -
SDLCONFIG=`which sdl-config || which sdl11-config || which sdl12-config || echo `
if [ -n "$SDLCONFIG" ] ; then
echo "SDL config is located at: $SDLCONFIG"
sed -e"s@XX_SDL_CONFIG_PLACEHOLDER_XX@$SDLCONFIG@g" < Jamfile.next > tmp && mv tmp Jamfile
else
echo "********************************"
echo "ERROR! SDL CONFIG WAS NOT FOUND!"
echo "********************************"
exit 1
fi
echo "Configure complete. Now use 'jam' to build"
echo "Add -sWITH_PNG=<dir to png.h> to build with PNG support"
echo "Add -sWITH_ZLIB=1 to enable zlib savegame support"
echo "Add -sRELEASE=1 to build an optimized executable"
echo "Add -sWITH_BONE_NETWORKING=1 to build with BeOS BONE networking support"
echo "Add -sBEOS_MIDI=1 to enable BeOS native MIDI (libmidi.so) music output"
echo ""
echo "For people using make:"
echo "write make (or gmake)"
echo "configure have nothing to do with the makefile"

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

@ -0,0 +1,980 @@
#include "stdafx.h"
#include "ttd.h"
#include "vehicle.h"
#include "command.h"
#include "news.h"
#include "gfx.h"
#include "station.h"
#include "town.h"
#include "industry.h"
#include "player.h"
#include "airport_movement.h"
static void DisasterClearSquare(uint tile)
{
int type;
if (!EnsureNoVehicle(tile))
return;
type = _map_type_and_height[tile] >> 4;
if (type == MP_RAILWAY) {
if (IS_HUMAN_PLAYER(_map_owner[tile]))
DoClearSquare(tile);
} else if (type == MP_HOUSE) {
byte p = _current_player;
_current_player = OWNER_NONE;
DoCommandByTile(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
_current_player = p;
} else if (type == MP_TREES || type == MP_CLEAR) {
DoClearSquare(tile);
}
}
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 = TILE_FROM_XY(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->next_order = 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 = TILE_FROM_XY(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;
uint tile;
++v->tick_counter;
if (v->next_order < 2) {
if (v->tick_counter&1)
return;
GetNewVehiclePos(v, &gp);
SetDisasterVehiclePos(v, gp.x, gp.y, v->z_pos);
if (v->next_order == 1) {
if (++v->age == 38) {
v->next_order = 2;
v->age = 0;
}
if ((v->tick_counter&7)==0) {
CreateEffectVehicleRel(v, 0, -17, 2, EV_SMOKE_3);
}
} else if (v->next_order == 0) {
tile = v->tile; /**/
if (IS_TILETYPE(tile, MP_STATION) &&
IS_BYTE_INSIDE(_map5[tile], 8, 0x43) &&
IS_HUMAN_PLAYER(_map_owner[tile])) {
v->next_order = 1;
v->age = 0;
SET_DPARAM16(0, _map2[tile]);
AddNewsItem(STR_B000_ZEPPELIN_DISASTER_AT,
NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_VEHICLE, NT_ACCIDENT, 0),
v->index,
0);
}
}
if (v->y_pos >= (TILES_Y+9) * 16 - 1)
DeleteDisasterVeh(v);
return;
}
if (v->next_order > 2) {
if (++v->age <= 13320)
return;
tile = v->tile; /**/
if (IS_TILETYPE(tile, MP_STATION) &&
IS_BYTE_INSIDE(_map5[tile], 8, 0x43) &&
IS_HUMAN_PLAYER(_map_owner[tile])) {
st = DEREF_STATION(_map2[tile]);
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_CRASHED_SMOKE);
SndPlayVehicleFx(0x10, v);
v->u.disaster.image_override = 0xF42;
} else if (v->age == 70) {
v->u.disaster.image_override = 0xF43;
} else if (v->age <= 300) {
if (!(v->tick_counter&7)) {
uint32 r = Random();
CreateEffectVehicleRel(v,
-7 + (r&0xF),
-7 + (r>>4&0xF),
5 + (r>>8&0x7),
EV_DEMOLISH);
}
} else if (v->age == 350) {
v->next_order = 3;
v->age = 0;
}
tile = v->tile;/**/
if (IS_TILETYPE(tile, MP_STATION) &&
IS_BYTE_INSIDE(_map5[tile], 8, 0x43) &&
IS_HUMAN_PLAYER(_map_owner[tile])) {
st = DEREF_STATION(_map2[tile]);
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) ? 0xF45 : 0xF44;
if (v->next_order == 0) {
// fly around randomly
int x = GET_TILE_X(v->dest_tile)*16;
int y = GET_TILE_Y(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 = TILE_MASK(Random());
return;
}
v->next_order = 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 = &_vehicles[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_CRASHED_SMOKE);
SndPlayVehicleFx(0x10, v);
DeleteDisasterVeh(v);
}
}
}
static void DestructIndustry(Industry *i)
{
uint tile;
byte index = i - _industries;
for(tile=0; tile != TILES_X*TILES_Y; tile++) {
if (IS_TILETYPE(tile, MP_INDUSTRY) && _map2[tile] == index) {
_map_owner[tile] = 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->next_order == 1 && v->tick_counter&4) ? 0xF4F : 0;
GetNewVehiclePos(v, &gp);
SetDisasterVehiclePos(v, gp.x, gp.y, v->z_pos);
if (gp.x < -160) {
DeleteDisasterVeh(v);
return;
}
if (v->next_order == 2) {
if (!(v->tick_counter&3)) {
Industry *i = DEREF_INDUSTRY(v->dest_tile);
int x = GET_TILE_X(i->xy)*16;
int y = GET_TILE_Y(i->xy)*16;
uint32 r = Random();
CreateEffectVehicleAbove(
x + (r & 0x3F),
y + (r >> 6 & 0x3F),
(r >> 12 & 0xF),
EV_DEMOLISH);
if (++v->age >= 55)
v->next_order = 3;
}
} else if (v->next_order == 1) {
if (++v->age == 112) {
Industry *i;
v->next_order = 2;
v->age = 0;
i = DEREF_INDUSTRY(v->dest_tile);
DestructIndustry(i);
SET_DPARAM16(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(0x10, i->xy);
}
} else if (v->next_order == 0) {
int x,y;
uint tile;
int ind;
x = v->x_pos - 15*16;
y = v->y_pos;
if ( (uint)x > (TILES_X-1) * 16-1)
return;
tile = TILE_FROM_XY(x,y);
if (!IS_TILETYPE(tile, MP_INDUSTRY))
return;
v->dest_tile = ind = _map2[tile];
if (DEREF_INDUSTRY(ind)->type == IT_OIL_REFINERY) {
v->next_order = 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->next_order == 1 && v->tick_counter&4) ? 0xF53 : 0;
GetNewVehiclePos(v, &gp);
SetDisasterVehiclePos(v, gp.x, gp.y, v->z_pos);
if (gp.x > TILES_X * 16 + 9*16 - 1) {
DeleteDisasterVeh(v);
return;
}
if (v->next_order == 2) {
if (!(v->tick_counter&3)) {
Industry *i = DEREF_INDUSTRY(v->dest_tile);
int x = GET_TILE_X(i->xy)*16;
int y = GET_TILE_Y(i->xy)*16;
uint32 r = Random();
CreateEffectVehicleAbove(
x + (r & 0x3F),
y + (r >> 6 & 0x3F),
(r >> 12 & 0xF),
EV_DEMOLISH);
if (++v->age >= 55)
v->next_order = 3;
}
} else if (v->next_order == 1) {
if (++v->age == 112) {
Industry *i;
v->next_order = 2;
v->age = 0;
i = DEREF_INDUSTRY(v->dest_tile);
DestructIndustry(i);
SET_DPARAM16(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(0x10, i->xy);
}
} else if (v->next_order == 0) {
int x,y;
uint tile;
int ind;
x = v->x_pos - 15*16;
y = v->y_pos;
if ( (uint)x > (TILES_X-1) * 16-1)
return;
tile = TILE_FROM_XY(x,y);
if (!IS_TILETYPE(tile, MP_INDUSTRY))
return;
v->dest_tile = ind = _map2[tile];
if (DEREF_INDUSTRY(ind)->type == IT_FACTORY) {
v->next_order = 1;
v->age = 0;
}
}
}
// Helicopter rotor blades
static void DisasterTick_3b(Vehicle *v)
{
if (++v->tick_counter & 1)
return;
if (++v->cur_image == 0xF40 + 1)
v->cur_image = 0xF3E;
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;
uint tile,tile_org;
v->tick_counter++;
if (v->next_order == 1) {
int x = GET_TILE_X(v->dest_tile)*16 + 8;
int y = GET_TILE_Y(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->next_order = 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);
SET_DPARAM16(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->next_order < 1) {
int x = GET_TILE_X(v->dest_tile)*16;
int y = GET_TILE_Y(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 = TILE_MASK(Random());
return;
}
v->next_order = 1;
tile_org = tile = TILE_MASK(Random());
do {
if (IS_TILETYPE(tile, MP_RAILWAY) &&
(_map5[tile]&~3)!=0xC0 && IS_HUMAN_PLAYER(_map_owner[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 > TILES_X * 16 + 9*16 - 1) {
DeleteDisasterVeh(v);
return;
}
if (v->next_order == 0) {
u = &_vehicles[v->u.disaster.unk2];
if (abs(v->x_pos - u->x_pos) > 16)
return;
v->next_order = 1;
CreateEffectVehicleRel(u, 0, 7, 8, EV_CRASHED_SMOKE);
SndPlayVehicleFx(0x10, u);
DeleteDisasterVeh(u);
for(i=0; i!=80; i++) {
uint32 r = Random();
CreateEffectVehicleAbove(
v->x_pos-32+(r&0x3F),
v->y_pos-32+(r>>5&0x3F),
0,
EV_DEMOLISH);
}
BEGIN_TILE_LOOP(tile,6,6,v->tile - TILE_XY(3,3))
tile = TILE_MASK(tile);
DisasterClearSquare(tile);
END_TILE_LOOP(tile,6,6,v->tile - TILE_XY(3,3))
}
}
// Submarine handler
static void DisasterTick_5_and_6(Vehicle *v)
{
uint32 r;
GetNewVehiclePosResult gp;
uint 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 + _tileoffs_by_dir[v->direction >> 1];
if (IsValidTile(tile) &&
(r=GetTileTrackStatus(tile,4),(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 + ((Random()&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 HandleClickOnDisasterVeh(Vehicle *v)
{
// not used
}
void OnNewDay_DisasterVehicle(Vehicle *v)
{
// not used
}
typedef void DisasterInitProc();
// Zeppeliner which crashes on a small airport
static void Disaster0_Init()
{
Vehicle *v = ForceAllocateSpecialVehicle(), *u;
Station *st;
int x;
if (v == NULL)
return;
for(st=_stations;;) {
if (st->xy && st->airport_tile != 0 &&
st->airport_type <= 1 &&
IS_HUMAN_PLAYER(st->owner)) {
x = (GET_TILE_X(st->xy) + 2) * 16;
break;
}
if (++st == endof(_stations)) {
x = (GET_TILE_X(Random())) * 16 + 8;
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()
{
Vehicle *v = ForceAllocateSpecialVehicle(), *u;
int x;
if (v == NULL)
return;
x = (GET_TILE_X(Random())) * 16 + 8;
InitializeDisasterVehicle(v, x, 0, 135, 3, 2);
v->dest_tile = TILE_XY(TILES_X/2,TILES_Y/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()
{
Industry *i, *found;
Vehicle *v,*u;
int x,y;
for(found=NULL,i=_industries; i != endof(_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 = (TILES_X+9) * 16 - 1;
y = GET_TILE_Y(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()
{
Industry *i, *found;
Vehicle *v,*u,*w;
int x,y;
for(found=NULL,i=_industries; i != endof(_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 = GET_TILE_Y(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()
{
Vehicle *v = ForceAllocateSpecialVehicle(), *u;
int x,y;
if (v == NULL)
return;
x = (GET_TILE_X(Random())) * 16 + 8;
y = (TILES_X-1)*16-1;
InitializeDisasterVehicle(v, x, y, 135, 7, 9);
v->dest_tile = TILE_XY(TILES_X/2,TILES_Y/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()
{
Vehicle *v = ForceAllocateSpecialVehicle();
int x,y;
byte dir;
uint32 r;
if (v == NULL)
return;
r = Random();
x = (GET_TILE_X(r)) * 16 + 8;
y = 8;
dir = 3;
if (r & 0x80000000) { y = (TILES_X-1) * 16 - 8 - 1; dir = 7; }
InitializeDisasterVehicle(v, x, y, 0, dir,13);
v->age = 0;
}
// Submarine type 2
static void Disaster6_Init()
{
Vehicle *v = ForceAllocateSpecialVehicle();
int x,y;
byte dir;
uint32 r;
if (v == NULL)
return;
r = Random();
x = (GET_TILE_X(r)) * 16 + 8;
y = 8;
dir = 3;
if (r & 0x80000000) { y = (TILES_X-1) * 16 - 8 - 1; dir = 7; }
InitializeDisasterVehicle(v, x, y, 0, dir,14);
v->age = 0;
}
static void Disaster7_Init()
{
Industry *i;
int maxloop = 15;
int index = Random() & 0xF;
do {
for(i=_industries; i != endof(_industries); i++) {
if (i->xy != 0 && i->type == IT_COAL_MINE && --index < 0) {
SET_DPARAM16(0, i->town->index);
AddNewsItem(STR_B005_COAL_MINE_SUBSIDENCE_LEAVES,
NEWS_FLAGS(NM_THIN,NF_VIEWPORT|NF_TILE,NT_ACCIDENT,0), i->xy + TILE_XY(1,1), 0);
{
uint tile = i->xy;
int step = _tileoffs_by_dir[Random() & 3];
int count = 30;
do {
DisasterClearSquare(tile);
tile = TILE_MASK(tile + step);
} while (--count);
}
return;
}
}
} while (--maxloop != 0);
}
static DisasterInitProc * const _disaster_initprocs[] = {
Disaster0_Init,
Disaster1_Init,
Disaster2_Init,
Disaster3_Init,
Disaster4_Init,
Disaster5_Init,
Disaster6_Init,
Disaster7_Init,
};
typedef struct {
byte min,max;
} DisasterYears;
#define MK(a,b) {a-20,b-20}
static const DisasterYears _dis_years[8] = {
MK(30,55),
MK(40,70),
MK(60,90),
MK(70,100),
MK(100,200),
MK(40,65),
MK(75,110),
MK(50,85),
};
void DoDisaster()
{
byte buf[8];
byte year = _cur_year;
int i,j;
for(i=j=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[(uint16)Random() * j >> 16]]();
}
static void ResetDisasterDelay()
{
_disaster_delay = (int)(Random() & 0x1FF) + 730;
}
void DisasterDailyLoop()
{
if (--_disaster_delay != 0)
return;
ResetDisasterDelay();
if (_opt.diff.disasters != 0)
DoDisaster();
}
void StartupDisasters() {
ResetDisasterDelay();
}

@ -0,0 +1,323 @@
#include "stdafx.h"
#include "ttd.h"
#include "window.h"
#include "gui.h"
#include "viewport.h"
#include "gfx.h"
#include "command.h"
static void ShowBuildDockStationPicker();
static void ShowBuildDocksDepotPicker();
static byte _ship_depot_direction;
static void CcBuildDocks(bool success, uint tile, uint32 p1, uint32 p2)
{
if (success) {
SndPlayTileFx(0, tile);
ResetObjectToPlace();
}
}
static void CcBuildCanal(bool success, uint tile, uint32 p1, uint32 p2)
{
if (success) { SndPlayTileFx(0, tile); }
}
static void PlaceDocks_Dock(uint tile)
{
DoCommandP(tile, 0, 0, CcBuildDocks, CMD_BUILD_DOCK | CMD_AUTO | CMD_MSG(STR_9802_CAN_T_BUILD_DOCK_HERE));
}
static void PlaceDocks_Depot(uint tile)
{
DoCommandP(tile, _ship_depot_direction, 0, CcBuildDocks, CMD_BUILD_SHIP_DEPOT | CMD_AUTO | CMD_MSG(STR_3802_CAN_T_BUILD_SHIP_DEPOT));
}
static void PlaceDocks_Buoy(uint tile)
{
DoCommandP(tile, 0, 0, CcBuildDocks, CMD_BUILD_BUOY | CMD_AUTO | CMD_MSG(STR_9835_CAN_T_POSITION_BUOY_HERE));
}
static void PlaceDocks_DemolishArea(uint tile)
{
VpStartPlaceSizing(tile, VPM_X_AND_Y);
}
static void PlaceDocks_BuildCanal(uint tile)
{
VpStartPlaceSizing(tile, VPM_X_OR_Y);
}
static void PlaceDocks_BuildLock(uint tile)
{
DoCommandP(tile, 0, 0, CcBuildDocks, CMD_BUILD_LOCK | CMD_AUTO | CMD_MSG(STR_CANT_BUILD_LOCKS));
}
static void BuildDocksClick_Dock(Window *w)
{
if (HandlePlacePushButton(w, 2, 0xE54, 3, PlaceDocks_Dock)) ShowBuildDockStationPicker();
}
static void BuildDocksClick_Depot(Window *w)
{
if (HandlePlacePushButton(w, 3, 0x2D1, 1, PlaceDocks_Depot)) ShowBuildDocksDepotPicker();
}
static void BuildDocksClick_Buoy(Window *w)
{
HandlePlacePushButton(w, 4, 0x2BE, 1, PlaceDocks_Buoy);
}
static void BuildDocksClick_Demolish(Window *w)
{
HandlePlacePushButton(w, 5, ANIMCURSOR_DEMOLISH, 1, PlaceDocks_DemolishArea);
}
static void BuildDocksClick_Lower(Window *w)
{
HandlePlacePushButton(w, 6, ANIMCURSOR_LOWERLAND, 2, PlaceProc_LowerLand);
}
static void BuildDocksClick_Raise(Window *w)
{
HandlePlacePushButton(w, 7, ANIMCURSOR_RAISELAND, 2, PlaceProc_RaiseLand);
}
static void BuildDocksClick_Purchase(Window *w)
{
HandlePlacePushButton(w, 8, 0x12B8, 1, PlaceProc_BuyLand);
}
static void BuildDocksClick_Canal(Window *w)
{
HandlePlacePushButton(w, 9, SPR_OPENTTD_BASE + 11, 1, PlaceDocks_BuildCanal);
}
static void BuildDocksClick_Lock(Window *w)
{
HandlePlacePushButton(w, 10, SPR_OPENTTD_BASE + 64, 1, PlaceDocks_BuildLock);
}
typedef void OnButtonClick(Window *w);
static OnButtonClick * const _build_docks_button_proc[] = {
BuildDocksClick_Dock,
BuildDocksClick_Depot,
BuildDocksClick_Buoy,
BuildDocksClick_Demolish,
BuildDocksClick_Lower,
BuildDocksClick_Raise,
BuildDocksClick_Purchase,
BuildDocksClick_Canal,
BuildDocksClick_Lock,
};
static void BuildDocksToolbWndProc(Window *w, WindowEvent *e)
{
switch(e->event) {
case WE_PAINT:
DrawWindowWidgets(w);
break;
case WE_CLICK: {
if (e->click.widget - 2 >= 0) _build_docks_button_proc[e->click.widget - 2](w);
} 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 == VPM_X_AND_Y)
DoCommandP(e->place.tile, e->place.starttile, 0, CcPlaySound10, CMD_CLEAR_AREA | CMD_MSG(STR_00B5_CAN_T_CLEAR_THIS_AREA));
else if(e->place.userdata == VPM_X_OR_Y)
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:
w->click_state = 0;
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: {
uint tile_from, tile_to;
tile_from = tile_to = e->place.tile;
switch(GetTileSlope(tile_from, NULL)) {
case 3: tile_to += TILE_XY(-1,0); break;
case 6: tile_to += TILE_XY(0,-1); break;
case 9: tile_to += TILE_XY(0,1); break;
case 12:tile_to += TILE_XY(1,0); break;
}
VpSetPresizeRange(tile_from, tile_to);
} break;
}
}
static const Widget _build_docks_toolb_widgets[] = {
{ WWT_CLOSEBOX, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, 7, 11, 197, 0, 13, STR_9801_DOCK_CONSTRUCTION, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PANEL, 7, 0, 21, 14, 35, 746, STR_981D_BUILD_SHIP_DOCK},
{ WWT_PANEL, 7, 22, 43, 14, 35, 748, STR_981E_BUILD_SHIP_DEPOT_FOR_BUILDING},
{ WWT_PANEL, 7, 44, 65, 14, 35, 693, STR_9834_POSITION_BUOY_WHICH_CAN},
{ WWT_PANEL, 7, 66, 87, 14, 35, 703, STR_018D_DEMOLISH_BUILDINGS_ETC},
{ WWT_PANEL, 7, 88, 109, 14, 35, 695, STR_018E_LOWER_A_CORNER_OF_LAND},
{ WWT_PANEL, 7, 110, 131, 14, 35, 694, STR_018F_RAISE_A_CORNER_OF_LAND},
{ WWT_PANEL, 7, 132, 153, 14, 35, 4791, STR_0329_PURCHASE_LAND_FOR_FUTURE},
{ WWT_PANEL, 7, 154, 175, 14, 35, SPR_OPENTTD_BASE+65, STR_BUILD_CANALS_TIP},
{ WWT_PANEL, 7, 176, 197, 14, 35, SPR_CANALS_BASE+69, STR_BUILD_LOCKS_TIP},
{ WWT_LAST},
};
static const WindowDesc _build_docks_toolbar_desc = {
640-197, 22, 198, 36,
WC_BUILD_TOOLBAR,0,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
_build_docks_toolb_widgets,
BuildDocksToolbWndProc
};
void ShowBuildDocksToolbar()
{
DeleteWindowById(WC_BUILD_TOOLBAR, 0);
AllocateWindowDesc(&_build_docks_toolbar_desc);
}
static void BuildDockStationWndProc(Window *w, WindowEvent *e)
{
switch(e->event) {
case WE_PAINT: {
if (WP(w,def_d).close)
return;
DrawWindowWidgets(w);
DrawStationCoverageAreaText(2, 15, (uint)-1);
} break;
case WE_CLICK: {
if (e->click.widget == 0) {
ResetObjectToPlace();
}
} break;
case WE_MOUSELOOP: {
if (WP(w,def_d).close) {
DeleteWindow(w);
return;
}
CheckRedrawStationCoverage(w);
break;
}
}
}
static const Widget _build_dock_station_widgets[] = {
{ WWT_CLOSEBOX, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, 7, 11, 147, 0, 13, STR_3068_DOCK, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PANEL, 7, 0, 147, 14, 45, 0x0, 0},
{ WWT_LAST},
};
static const WindowDesc _build_dock_station_desc = {
-1, -1, 148, 46,
WC_BUILD_STATION,WC_BUILD_TOOLBAR,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
_build_dock_station_widgets,
BuildDockStationWndProc
};
static void ShowBuildDockStationPicker()
{
AllocateWindowDesc(&_build_dock_station_desc);
}
static void UpdateDocksDirection()
{
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 0:
ResetObjectToPlace();
break;
case 3:
case 4:
_ship_depot_direction = e->click.widget - 3;
SndPlayFx(0x13);
UpdateDocksDirection();
SetWindowDirty(w);
break;
}
} break;
case WE_MOUSELOOP:
if (WP(w,def_d).close)
DeleteWindow(w);
break;
}
}
static const Widget _build_docks_depot_widgets[] = {
{ WWT_CLOSEBOX, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, 7, 11, 203, 0, 13, STR_3800_SHIP_DEPOT_ORIENTATION, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PANEL, 7, 0, 203, 14, 85, 0x0, 0},
{ WWT_PANEL, 14, 3, 100, 17, 82, 0x0, STR_3803_SELECT_SHIP_DEPOT_ORIENTATION},
{ WWT_PANEL, 14, 103, 200, 17, 82, 0x0, STR_3803_SELECT_SHIP_DEPOT_ORIENTATION},
{ WWT_LAST},
};
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()
{
AllocateWindowDesc(&_build_docks_depot_desc);
UpdateDocksDirection();
}
void InitializeDockGui()
{
_ship_depot_direction = 0;
}

@ -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

@ -0,0 +1,101 @@
Welcome to the manual for OpenTTD. The latest release version at the time of writing is 0.3.2.
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.
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.
Once you have obtained a recent copy of the source, you must build it. Windows build instructions will be provided later.
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:
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 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".
If you want MIDI music, copy the 'gm' folder from the original game directory/CD to the OpenTTD folder.
1.3 Running OpenTTD.
On Windows, you can use a third-party launcher such as OTTD-Launcher to run OpenTTD directly from Explorer. Otherwise, navigate via the command prompt to the correct location and launch ttd.exe.
On Linux, navigate at the shell to the correct location and run ttd.
On BeOS and Mac OS-X, just double click the ttd binary in the Tracker/Finder. You can also start from the shell.
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.
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.
Game Settings lets you set regional settings - currency, language, town names, etc. It also lets you select the resolution to run the game at, as well as the screenshot format to use.
Configure Patches lets you select which patches to use in the game. This allows you ro set the game play to either original Transport Tycoon Deluxe compatible mode or a mode more like playing under TTD-Patch. Patches include building on slopes, longer bridges, longer trains, pre-signals, and TTD-Patch compatible handling of non-stop orders.
2.1 Gameplay
This section of the manual is written with the assumption that you already know the gameplay basics of Transport Tycoon Deluxe, on either DOS or Windows. As you must have the Windows Transport Tycoon Deluxe CD to play OpenTTD, you should either have a paper manual or the complete manual in PDF format on the disk. This section will only cover the gameplay differences from Transport Tycoon Deluxe.
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.
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.
2.4 Freeform Rail Laying.
Along side the other rail laying buttons, you will see a button that looks somewhat like a crossing. This is the freeform rail laying tool., and it allows you to drag rail in any direction to lay it. This has a number of advantages, one of the main ones being that it can seriously speed up the laying of diagonal tracks.
2.5 Vehicle Queuing (with Quantum Effects)
This useful addition to OpenTTD means that road vehicles will queue outside a road station to wait for a space rather than attempt to enter it immediately. As anyone who has operated a large road network with busy stations will know, road vehicles quickly pile up inside stations. This will prevent that. The Quantum Effects are down to a bug in the game that means that mutliple vehicles will often only take up one space in the queue. However, this is almost too useful to fix, and should still be there in later versions. This can be enabled/disabled.
2.6 Building On Slopes
This allows you to build roads, rails, stations and depots on slopes. It also allows the construction of trasmitters and lighthouses on slopes in the scenario editor. There are some minor differences between OpenTTD's and TTD-Patch's handling of building on slopes, the main one being that bridges must still have solid land at their endings.
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.
2.8 Long trains
OpenTTD allows trains of around 60 cars length, hence allowing you to use 7 square stations to their capacity and beyond.
2.9 Speed Display
This addition to OpenTTD allows you to see the current speed of any vehicle in their status window. Just open the status window of a vehicle and you can see the speed at that given moment. This allows you to see wheter better bridges, flatter/straighter track or more powerful engines could be used to increase the speed of a vehicle
2.10 More Trains, More Ships, More Everything!
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
OpenTTD now supports rudimentary TCP/IP based network play. This is not supported on all platforms. To start a server, use the '-n' CLI switch, and start a client with '-n' and the servers IP adress. The OpenTTD network play runs over port 12345, so you may need to open this on your firewall.
2.12 Rail Recycling.
This button, at the end of the train construction window, lets you 'recycle' track to a new type. It also works on bridges, tunnels, stations and depots.
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.

@ -0,0 +1,38 @@
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
The first thing you need to do is to get the error message. You can access OSX's build-in log by double-clicking Crash_Log_Opener. OTTD will do that if that file is present in the same folder as OTTD and is not renamed. However, major crashes can prevent the autoopen feature and you have to do it manually then
If Crash_Log_Opener doesn't work you can view the log by opening Console inside Applications/utilities.
If you use the Console app, you should look at the buttom of the console.log window
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

@ -0,0 +1,60 @@
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 the WINDOWS version of Transport Tycoon Deluxe to openttd/data/
sample.cat
trg1r.grf
trgcr.grf
trghr.grf
trgir.grf
trgtr.grf
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 $

@ -0,0 +1,89 @@
Compilung OpenTTD using MS VC6.0
Step 1
------------------
Downloaded:
Useful.zip http://sourceforge.net/project/showfiles.php?group_id=103924&package_id=114307&release_id=228633
SDL.zip http://www.libsdl.org/release/SDL-1.2.7-win32.zip
DirectX7.0 SDK http://www.tt-forums.net/download.php?id=15989
(or alternatively the latest DirectX SDK from Microsoft)
afxres.h http://www-d0.fnal.gov/d0dist/dist/packages/d0ve/devel/windows/AFXRES.H
Step 2
------------------
Put the newly downloaded files in the VC lib and include directories
(Where D:\program files\ is your local location of VC)
* zconf.h [useful.zip]
* zlib.h [useful.zip]
* afxres.h
in
D:\Program Files\Microsoft Visual Studio\VC98\Include
* zlibstat.lib [usefull.zip]
* SDL.lib [SDL.zip
* libpng.lib [usefull.zip]
in
D:\Program Files\Microsoft Visual Studio\VC98\Lib
You can also make custum directories, 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: D:\Program Files\Microsoft Visual Studio\VC98\DirectX 7 SDK\include )
b) library files (the lib dir, D:\Program Files\Microsoft Visual Studio\VC98\DirectX 7 SDK\lib )
Step 3: DirextX SDK
------------------
(This should work with the latest DirectX SDK as well.)
The installation with DirectX 7 was odd, so you'd better use the version available via the forum, see also
the download link on top.
Copy the DirectX 7 SDK files, leaving the directory stucture intact, to the directory:
D:\Program Files\Microsoft Visual Studio\VC98\
thus resulting in
D:\Program Files\Microsoft Visual Studio\VC98\DirectX 7 SDK\include and
D:\Program Files\Microsoft Visual Studio\VC98\DirectX 7 SDK\lib
Step 3.1
Add these two folders to the search path of VC.
In VC6.0: Tools -> Options -> Directories -> show directories for:
a) include files (the include dir: D:\Program Files\Microsoft Visual Studio\VC98\DirectX 7 SDK\include )
b) libraru files (the lib dir, D:\Program Files\Microsoft Visual Studio\VC98\DirectX 7 SDK\lib )
Step 4
-----------------
Copy the following files from the WINDOWS version of Transport Tycoon Deluxe to the data folder
sample.cat
trg1r.grf
trgcr.grf
trghr.grf
trgir.grf
trgtr.grf
Step 5
-----------------
Compile ...
Step 6
-----------------
Now it should work, it worked for me :)
Go ahead and make that patch!
Happy Hacking!
------------------
written by Dribbel

@ -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

@ -0,0 +1,611 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<html>
<head>
<meta name="Author" content="Marcin Grzegorczyk">
<meta name="Description" content="Structure of Transport Tycoon Deluxe (TTD) savegame files">
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>Transport Tycoon Deluxe savegame internals</title>
</head>
<body>
<h3><a name="Landscape">Landscape</a></h3>
<p>
Five arrays are used to encode the information of the contents of each tile. These arrays are referred to as <a href="#_landscape1">map_owner</a>, <a href="#_landscape2">map2</a>, <a href="#_landscape3">map3_lo</a>, <a href="#_landscape4">type_and_height</a> and <a href="#_landscape5">map5</a>. The known encodings are listed in the table below. The most important value is the class of a tile, stored in the upper 4 bits of the type_and_height array.
</p>
<p>
<a name="OwnershipInfo">Owner values</a> <tt>00</tt> through <tt>07</tt> are companies (they're indices into the <a href="#_CompanyArray">array of companies</a>), <tt>10</tt> is no owner, <tt>11</tt> appears to be reserved for water, <tt>80</tt> and above are towns (in this case the low 7 bits contain an index into the <a href="#_TownArray">town array</a>).
</p>
<p>
TTD's class-specific periodic tile processing routine is called once every +256 ticks for each tile.
</p>
<table border=1 cellpadding=3>
<tr><th align=left>Class</th><th align=left>Meaning & details of encoding</th></tr>
<tr><td valign=top nowrap><a name="Class0"><tt> 0 </tt></a></td><td>
<ul>
<li>map5 bits 4..0: tile type:
<table>
<tr><td nowrap valign=top><tt>00</tt>&nbsp; </td><td align=left>bare land</td></tr>
<tr><td nowrap valign=top><tt>01</tt>&nbsp; </td><td align=left>1/3 grass</td></tr>
<tr><td nowrap valign=top><tt>02</tt>&nbsp; </td><td align=left>2/3 grass</td></tr>
<tr><td nowrap valign=top><tt>03</tt>&nbsp; </td><td align=left>full grass</td></tr>
<tr><td nowrap valign=top><tt>07</tt>&nbsp; </td><td align=left>rough land</td></tr>
<tr><td nowrap valign=top><tt>0B</tt>&nbsp; </td><td align=left>rocks</td></tr>
<tr><td nowrap valign=top><tt>0F</tt>&nbsp; </td><td align=left>fields; type of fields in map3_lo bits 3..0 (legal values: 0 through 9)</td></tr>
<tr><td nowrap valign=top><tt>10</tt>&nbsp; </td><td align=left>1/4 snow</td></tr>
<tr><td nowrap valign=top><tt>11</tt>&nbsp; </td><td align=left>2/4 snow</td></tr>
<tr><td nowrap valign=top><tt>12</tt>&nbsp; </td><td align=left>3/4 snow</td></tr>
<tr><td nowrap valign=top><tt>13</tt>&nbsp; </td><td align=left>full snow</td></tr>
<tr><td nowrap valign=top><tt>15</tt>&nbsp; </td><td align=left>partial desert</td></tr>
<tr><td nowrap valign=top><tt>17</tt>&nbsp; </td><td align=left>full desert</td></tr>
</table>
</li>
<li>map5 bits 7..6: update counter, incremented on every periodic processing for tile types other than <tt>03</tt>, <tt>07</tt>, <tt>0B</tt> and <tt>10</tt> and above, on wraparound the tile is updated (for fields, the type of fields in map3_lo is increased, for other types the tile type in map5 is increased)
<br>(for snow and desert, these bits are not used, tile is updated on every periodic processing)
</li>
<li>map_owner: <a href="#OwnershipInfo">owner</a> of the tile (normally <tt>10</tt>)
</li>
<li>map3_hi bits 7..5: type of hedge on the SW border of the tile (1 through 6, or 0=none); bits 4..2: same for the SE border
</li>
</ul>
</td></tr>
<tr><td valign=top nowrap><a name="Class1"><tt> 1 </tt></a></td><td>
map5 bit 7 clear: railway track
<ul>
<li>map5 bits 0..5: track layout: bit set = track present:
<table>
<tr><td nowrap valign=top>bit 0: </td><td align=left>in the X direction</td></tr>
<tr><td nowrap valign=top>bit 1: </td><td align=left>in the Y direction</td></tr>
<tr><td nowrap valign=top>bit 2: </td><td align=left>in the north corner (direction W-E)</td></tr>
<tr><td nowrap valign=top>bit 3: </td><td align=left>in the south corner (direction W-E)</td></tr>
<tr><td nowrap valign=top>bit 4: </td><td align=left>in the west corner (direction N-S)</td></tr>
<tr><td nowrap valign=top>bit 5: </td><td align=left>in the east corner (direction N-S)</td></tr>
</table></li>
<li>map5 bit 6 set = with signals:
<ul>
<li>map3_lo bits 7..4: bit set = signal present:
<ul>
<li>For track in the X direction:
<table>
<tr><td nowrap valign=top>bit 6: </td><td align=left>signal in the SW direction</td></tr>
<tr><td nowrap valign=top>bit 7: </td><td align=left>signal in the NE direction</td></tr>
</table></li>
<li>For track in the Y direction:
<table>
<tr><td nowrap valign=top>bit 6: </td><td align=left>signal in the NW direction</td></tr>
<tr><td nowrap valign=top>bit 7: </td><td align=left>signal in the SE direction</td></tr>
</table></li>
<li>For tracks in the W-E direction:
<table>
<tr><td nowrap valign=top>bit 4: </td><td align=left>signal in the W direction on the track in the S corner</td></tr>
<tr><td nowrap valign=top>bit 5: </td><td align=left>signal in the E direction on the track in the S corner</td></tr>
<tr><td nowrap valign=top>bit 6: </td><td align=left>signal in the W direction on the track in the N corner</td></tr>
<tr><td nowrap valign=top>bit 7: </td><td align=left>signal in the E direction on the track in the N corner</td></tr>
</table></li>
<li>For tracks in the N-S direction:
<table>
<tr><td nowrap valign=top>bit 4: </td><td align=left>signal in the S direction on the track in the E corner</td></tr>
<tr><td nowrap valign=top>bit 5: </td><td align=left>signal in the N direction on the track in the E corner</td></tr>
<tr><td nowrap valign=top>bit 6: </td><td align=left>signal in the S direction on the track in the W corner</td></tr>
<tr><td nowrap valign=top>bit 7: </td><td align=left>signal in the N direction on the track in the W corner</td></tr>
</table></li>
</ul></li>
<li>map2 bits 7..4: bit clear = signal shows red; same bits as in map3_lo</li>
<li>OpenTTD bits in map3_hi:
<table>
<tr><td nowrap valign=top>bits 1..0: </td><td align=left>type of signal:</td></tr>
<tr><td nowrap valign=top><tt>00</tt>: </td><td align=left>normal signals</td></tr>
<tr><td nowrap valign=top><tt>01</tt>: </td><td align=left>pre-signals</td></tr>
<tr><td nowrap valign=top><tt>10</tt>: </td><td align=left>exit-signals</td></tr>
<tr><td nowrap valign=top><tt>11</tt>: </td><td align=left>combo-signals</td></tr>
<tr><td nowrap valign=top>bit 2: </td><td align=left>set = semaphore signals, clear = light signals</td></tr>
</table></li>
</ul></li>
<li>map_owner: <a href="#OwnershipInfo">owner</a> of the track
</li>
<li>map2 bits 0..3:
<table>
<tr><td nowrap valign=top><tt>0</tt>&nbsp; </td><td align=left>on bare land</td></tr>
<tr><td nowrap valign=top><tt>1</tt>&nbsp; </td><td align=left>on grass, no fences</td></tr>
<tr><td nowrap valign=top><tt>2</tt>&nbsp; </td><td align=left>fence on the NW side</td></tr>
<tr><td nowrap valign=top><tt>3</tt>&nbsp; </td><td align=left>fence on the SE side</td></tr>
<tr><td nowrap valign=top><tt>4</tt>&nbsp; </td><td align=left>fences on the NW and SE sides</td></tr>
<tr><td nowrap valign=top><tt>5</tt>&nbsp; </td><td align=left>fence on the NE side</td></tr>
<tr><td nowrap valign=top><tt>6</tt>&nbsp; </td><td align=left>fence on the SW side</td></tr>
<tr><td nowrap valign=top><tt>7</tt>&nbsp; </td><td align=left>fences on the NE and SW sides</td></tr>
<tr><td nowrap valign=top><tt>8</tt>&nbsp; </td><td align=left>fence on the E side (track in the W corner)</td></tr>
<tr><td nowrap valign=top><tt>9</tt>&nbsp; </td><td align=left>fence on the W side (track in the E corner)</td></tr>
<tr><td nowrap valign=top><tt>A</tt>&nbsp; </td><td align=left>fence on the S side (track in the N corner)</td></tr>
<tr><td nowrap valign=top><tt>B</tt>&nbsp; </td><td align=left>fence on the N side (track in the S corner)</td></tr>
<tr><td nowrap valign=top><tt>C</tt>&nbsp; </td><td align=left>on snow or desert</td></tr>
</table></li>
<li>map3_lo bits 0..3 = <a name="TrackType">track type</a>: <tt>0</tt> - conventional railway, <tt>1</tt> - monorail, <tt>2</tt> - maglev
</li>
</ul>
map5 bits 7 and 6 set: railway depot / checkpoints
<ul>
<li>map5 value C0..C3: railway depot
<br>map5 bits 1..0 - direction: exit towards: <tt>00</tt> = NE, <tt>01</tt> = SE, <tt>02</tt> = SW, <tt>03</tt> = NW</li>
<li>map5 value C4..C5: checkpoint
<br>bit 0: clear = in X direction, set = in Y direction
<br>
<br>
<li>map_owner: <a href="#OwnershipInfo">owner</a> of the depot / checkpoint</li>
<li>map3_lo bits 0..3 = <a href="#TrackType">track type</a></li>
</ul>
</td></tr>
<tr><td valign=top nowrap><a name="Class2"><tt> 2 </tt></a></td><td>
map5 bits 7..4 clear: road
<ul>
<li>map5 bits 3..0: road layout: bit set = road piece present:
<table>
<tr><td nowrap valign=top>bit 0: </td><td align=left>NW piece</td></tr>
<tr><td nowrap valign=top>bit 1: </td><td align=left>SW piece</td></tr>
<tr><td nowrap valign=top>bit 2: </td><td align=left>SE piece</td></tr>
<tr><td nowrap valign=top>bit 3: </td><td align=left>NE piece</td></tr>
</table></li>
<li>map_owner: <a href="#OwnershipInfo">owner</a> of the road</li>
<li>map2 bits 0..2: <tt>0</tt> - on bare land, <tt>1</tt> - on grass, <tt>2</tt> - paved, <tt>3</tt> - with streetlights, <tt>5</tt> - tree-lined, <tt>6</tt> - on grass with road works, <tt>7</tt> - paved with road works</li>
<li>map3_hi bit 7 set = on snow or desert</li>
</ul>
map5 bit 4 set, bits 7..5 clear: level crossing
<ul>
<li>map5 bit 3: clear - road in the X direction, set - road in the Y direction (railway track always perpendicular)</li>
<li>map5 bit 2: set if crossing lights are on</li>
<li>map_owner: <a href="#OwnershipInfo">owner</a> of the railway track</li>
<li>map2 bits 0..2: <tt>0</tt> - on bare land, <tt>1</tt> - on grass, <tt>2</tt> or higher - paved</li>
<li>map3_lo bits 0..7: <a href="#OwnershipInfo">owner</a> of the road</li>
<li>map3_hi bits 3..0: <a href="#TrackType">track type</a></li>
<li>map3_hi bit 7 set = on snow or desert</li>
</ul>
map5 bit 5 set: road depot
<ul>
<li>map5 bits 3..0 - direction: exit towards: <tt>0</tt> = NE, <tt>1</tt> = SE, <tt>2</tt> = SW, <tt>3</tt> = NW</li>
<li>map_owner: <a href="#OwnershipInfo">owner</a> of the depot</li>
<li>map3_hi bit 7 set = on snow or desert (not displayed, but set internally)</li>
</ul>
</td></tr>
<tr><td valign=top nowrap><a name="Class3"><tt> 3 </tt></a></td><td>
Town building
<ul>
<li>map2: <a name="HouseTypes">town building type</a>:
<p><small>Note: In the climate list, 'sub-arctic' means below the <a href="#_snowline">snow line</a>, and 'snow' means above the snow line in the sub-arctic climate.</small></p>
<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>
<tr><td colspan=2></td></tr> <!-- spacer -- -- (and I don't mean a walk) -->
</table></li>
<li>map3_lo bits 7..6: stage of construction (<tt>3</tt> = completed)</li>
<li>map5 bits 2..0: construction counter, for buildings under construction incremented on every periodic tile processing, on wraparound the stage of construction in map3_lo is increased</li>
<li>for large office blocks (types <tt>04</tt> and <tt>05</tt>):
<ul>
<li>map_owner bits 6..0: position of the lift</li>
<li>map_owner bit 7: if set the lift is moving</li>
<li>map5 bit 7: if set then map5 bits 5..0 hold the final position of the lift divided by 6 (valid values 0..6 except 1)</li>
</ul></li>
</ul>
</td></tr>
<tr><td valign=top nowrap><a name="Class4"><tt> 4 </tt></a></td><td>
Trees
<ul>
<li>map5 bits 7..6: number of trees minus one</li>
<li>map5 bits 2..0: growth status: <tt>0</tt>..<tt>2</tt> - one of trees is growing, <tt>3</tt> - all trees are fully grown, <tt>4</tt>..<tt>6</tt> - one of trees is withering</li>
<li>map3_lo bits 7..0: type of trees:
<table>
<tr><td nowrap valign=top><tt>00</tt>..<tt>0B</tt>&nbsp; </td><td align=left>temperate climate trees</td></tr>
<tr><td nowrap valign=top><tt>0C</tt>..<tt>13</tt>&nbsp; </td><td align=left>sub-arctic climate trees</td></tr>
<tr><td nowrap valign=top><tt>14</tt>..<tt>1A</tt>&nbsp; </td><td align=left>rainforest trees</td></tr>
<tr><td nowrap valign=top><tt>1B</tt> </td><td align=left>cactus plants</td></tr>
<tr><td nowrap valign=top><tt>1C</tt>..<tt>1F</tt>&nbsp; </td><td align=left>sub-tropical climate, non-rainforest, non-desert trees</td></tr>
<tr><td nowrap valign=top><tt>20</tt>..<tt>28</tt>&nbsp; </td><td align=left>toyland trees</td></tr>
</table>
(note: the actually displayed set of trees depends on both type and number of trees)
</li>
<li>map3_hi bits 7..5: type of hedge on the SW border of the tile (1 through 6, or 0=none)</li>
<li>map3_hi bits 4..2: type of hedge on the SE border of the tile (1 through 6, or 0=none)</li>
<li>map2 bits 5..4:
<table>
<tr><td nowrap valign=top><tt>0</tt>&nbsp; </td><td align=left>on grass</td></tr>
<tr><td nowrap valign=top><tt>1</tt>&nbsp; </td><td align=left>on rough land</td></tr>
<tr><td nowrap valign=top><tt>2</tt>&nbsp; </td><td align=left>on snow or desert; map2 bits 7..6 - amount of snow or desert (for desert always set to 3 in TTD)
</td></tr>
</table></li>
<li>map2 bits 3..0: update counter, incremented on every periodic processing, on wraparound the growth status is updated (or, if it's <tt>3</tt>, a random action is taken)</li>
<li>map_owner: <a href="#OwnershipInfo">owner</a> (normally <tt>10</tt>)</li>
</ul>
</td></tr>
<tr><td valign=top nowrap><a name="Class5"><tt> 5 </tt></a></td><td>
Station tile
<ul>
<li>map5: tile type:
<table>
<tr><td nowrap valign=top><tt>00</tt>..<tt>07</tt>&nbsp; </td><td align=left>railway station
<br><tt>00</tt>..<tt>01</tt> - open platform, <tt>02</tt>..<tt>03</tt> - open platform with station building, <tt>04</tt>....<tt>07</tt> - roofed platform
<br>bit 0: clear = in X direction, set = in Y direction
</td></tr>
<tr><td nowrap valign=top><tt>08</tt>..<tt>33</tt>&nbsp; </td><td align=left>large airport
<table>
<tr><td nowrap valign=top><tt>0B</tt>&nbsp; </td><td align=left>pad 1</td></tr>
<tr><td nowrap valign=top><tt>16</tt>..<tt>19</tt>&nbsp; </td><td align=left>runway middle</td></tr>
<tr><td nowrap valign=top><tt>1A</tt>&nbsp; </td><td align=left>runway ending</td></tr>
<tr><td nowrap valign=top><tt>1C</tt>&nbsp; </td><td align=left>control tower</td></tr>
<tr><td nowrap valign=top><tt>20</tt>&nbsp; </td><td align=left>hangar</td></tr>
<tr><td nowrap valign=top><tt>21</tt>&nbsp; </td><td align=left>pad 3</td></tr>
<tr><td nowrap valign=top><tt>22</tt>&nbsp; </td><td align=left>pad 2</td></tr>
<tr><td nowrap valign=top><tt>27</tt>..<tt>32</tt>&nbsp; </td><td align=left>radar (animated)</td></tr>
<tr><td nowrap valign=top><tt>33</tt>&nbsp; </td><td align=left>transmitter</td></tr>
</table>
The initial layout of a large airport is (rows in Y direction, columns in X direction):
<pre>
1F 1B 1E 33 26 1A
09 24 0B 0C 0D 16
21 1D 23 0E 0F 17
09 22 0D 11 10 18
09 08 14 13 12 19
20 0A 15 1C 27 1A
</pre>
</td></tr>
<tr><td nowrap valign=top><tt>34</tt>..<tt>41</tt>&nbsp; </td><td align=left>small airport
<table>
<tr><td nowrap valign=top><tt>3A</tt>..<tt>3D</tt>&nbsp; </td><td align=left>field with the wind meter (animated)</td></tr>
<tr><td nowrap valign=top><tt>3E</tt>&nbsp; </td><td align=left>runway south ending</td></tr>
<tr><td nowrap valign=top><tt>3F</tt>&nbsp; </td><td align=left>runway middle</td></tr>
<tr><td nowrap valign=top><tt>40</tt>&nbsp; </td><td align=left>runway north ending</td></tr>
<tr><td nowrap valign=top><tt>41</tt>&nbsp; </td><td align=left>hangar</td></tr>
</table>
The initial layout of a small airport is (rows in Y direction, columns in X direction):
<pre>
36 3A 40
35 39 3F
34 38 3F
41 37 3E
</pre>
</td></tr>
<tr><td nowrap valign=top><tt>42</tt> </td><td align=left>heliport</td></tr>
<tr><td nowrap valign=top><tt>43</tt>..<tt>46</tt>&nbsp; </td><td align=left>lorry loading area;
exit towards: <tt>43</tt> - NE, <tt>44</tt> - SE, <tt>45</tt> - SW, <tt>46</tt> - NW
</td></tr>
<tr><td nowrap valign=top><tt>47</tt>..<tt>4A</tt>&nbsp; </td><td align=left>bus station;
exit towards: <tt>47</tt> - NE, <tt>48</tt> - SE, <tt>49</tt> - SW, <tt>4A</tt> - NW
<tr><td nowrap valign=top><tt>4B</tt> </td><td align=left>oilfield</td></tr>
<tr><td nowrap valign=top><tt>4C</tt>..<tt>51</tt>&nbsp; </td><td align=left>ship dock;
<tt>4C</tt> - SW coast part, <tt>4D</tt> - NW coast part, <tt>4E</tt> - NE coast part, <tt>4F</tt> - SE coast part, <tt>50</tt> - X direction water part, <tt>51</tt> - Y direction water part
<tr><td nowrap valign=top><tt>52</tt> </td><td align=left>buoy</td></tr>
</td></tr>
<tr><td colspan=2></td></tr> <!-- spacer -->
</table>
</li>
<li>map_owner: <a href="#OwnershipInfo">owner</a> of the station</li>
<li>map2: index into the <a href="#_StationArray">array of stations</a></li>
<li>map3_lo bits 0..3: <a href="#TrackType">track type</a> for railway stations, must be 0 for all the other stations</li>
</ul>
</td></tr>
<tr><td valign=top nowrap><a name="Class6"><tt> 6 </tt></a></td><td>
<ul>
<li>map5: tile type:
<table>
<tr><td nowrap valign=top><tt>00</tt>&nbsp; </td><td align=left>water</td></tr>
<tr><td nowrap valign=top><tt>01</tt>&nbsp; </td><td align=left>coast or riverbank</td></tr>
<tr><td nowrap valign=top><tt>10</tt>..<tt>1B</tt>&nbsp; </td><td align=left>canal locks
<table>
<tr><td nowrap valign=top><tt>10</tt>&nbsp; </td><td align=left>middle part, (SW-NE direction)
<tr><td nowrap valign=top><tt>11</tt>&nbsp; </td><td align=left>middle part, (NW-SE direction)
<tr><td nowrap valign=top><tt>12</tt>&nbsp; </td><td align=left>middle part, (NE-SW direction)
<tr><td nowrap valign=top><tt>13</tt>&nbsp; </td><td align=left>middle part, (SE-NW direction)
<tr><td nowrap valign=top><tt>14</tt>&nbsp; </td><td align=left>lower part, (SW-NE direction)
<tr><td nowrap valign=top><tt>15</tt>&nbsp; </td><td align=left>lower part, (NW-SE direction)
<tr><td nowrap valign=top><tt>16</tt>&nbsp; </td><td align=left>lower part, (NE-SW direction)
<tr><td nowrap valign=top><tt>17</tt>&nbsp; </td><td align=left>lower part, (SE-NW direction)
<tr><td nowrap valign=top><tt>18</tt>&nbsp; </td><td align=left>upper part, (SW-NE direction)
<tr><td nowrap valign=top><tt>19</tt>&nbsp; </td><td align=left>upper part, (NW-SE direction)
<tr><td nowrap valign=top><tt>1A</tt>&nbsp; </td><td align=left>upper part, (NE-SW direction)
<tr><td nowrap valign=top><tt>1B</tt>&nbsp; </td><td align=left>upper part, (SE-NW direction)
</table>
<tr><td nowrap valign=top><tt>80</tt>..<tt>83</tt>&nbsp; </td><td align=left>ship depots
<table>
<tr><td nowrap valign=top><tt>80</tt>&nbsp; </td><td align=left>ship depot, NE part (X direction)
<tr><td nowrap valign=top><tt>81</tt>&nbsp; </td><td align=left>ship depot, SW part (X direction)
<tr><td nowrap valign=top><tt>82</tt>&nbsp; </td><td align=left>ship depot, NW part (Y direction)
<tr><td nowrap valign=top><tt>83</tt>&nbsp; </td><td align=left>ship depot, SE part (Y direction)
</td></tr>
</table>
</td></tr>
</table></li>
<li>map_owner: <a href="#OwnershipInfo">owner</a> (for water and coasts normally <tt>11</tt>)</li>
</ul>
</td></tr>
<tr><td valign=top nowrap><a name="Class7"><tt> 7 </tt></a></td><td>
Void
<p>
Tiles of this class form an invisible, one tile wide border at the south (bottom) edges of the map, so as to protect several algorithms from the consequences of a wraparound at the edges.
</p>
</td></tr>
<tr><td valign=top nowrap><a name="Class8"><tt> 8 </tt></a></td><td>
Industry tile
<ul>
<li>map5: type:
<br><small>(note: this is not the same as the <a href="#industry.type">industry type</a> stored in the <a href="#_IndustryArray">array of industries</a>)</small>
<table>
<tr><td nowrap valign=top><tt>00</tt>..<tt>06</tt>&nbsp; </td><td align=left>coal mine
<table>
<tr><td nowrap valign=top><tt>00</tt>&nbsp; </td><td align=left>wheel tower when not animated</td></tr>
<tr><td nowrap valign=top><tt>01</tt>&nbsp; </td><td align=left>wheel tower when animated; animation state in map_owner bits 5..0; map_owner bit 6 set = sound already generated</td></tr>
</table>
</td></tr>
<tr><td nowrap valign=top><tt>07</tt>..<tt>0A</tt>&nbsp; </td><td align=left>power station
<table>
<tr><td nowrap valign=top><tt>08</tt>&nbsp; </td><td align=left>chimney</td></tr>
<tr><td nowrap valign=top><tt>0A</tt>&nbsp; </td><td align=left>transformer; animation progress in map_owner bits 5..2 (valid range <tt>0</tt>..<tt>7</tt>)</td></tr>
</table>
</td></tr>
<tr><td nowrap valign=top><tt>0B</tt>..<tt>0F</tt>&nbsp; </td><td align=left>sawmill</td></tr>
<tr><td nowrap valign=top><tt>10</tt>..<tt>11</tt>&nbsp; </td><td align=left>forest
<table>
<tr><td nowrap valign=top><tt>11</tt>&nbsp; </td><td align=left>trees cut down</td></tr>
</table>
</td></tr>
<tr><td nowrap valign=top><tt>12</tt>..<tt>17</tt>&nbsp; </td><td align=left>oil refinery</td></tr>
<tr><td nowrap valign=top><tt>18</tt>..<tt>1C</tt>&nbsp; </td><td align=left>oil rig</td></tr>
<tr><td nowrap valign=top><tt>1D</tt>..<tt>20</tt>&nbsp; </td><td align=left>oil wells
<table>
<tr><td nowrap valign=top><tt>1D</tt>&nbsp; </td><td align=left>not animated</td></tr>
<tr><td nowrap valign=top><tt>1E</tt>..<tt>20</tt>&nbsp; </td><td align=left>various stages of animation; progress of animation in map_owner bits 1..0</td></tr>
</table>
</td></tr>
<tr><td nowrap valign=top><tt>21</tt>..<tt>26</tt>&nbsp; </td><td align=left>farm</td></tr>
<tr><td nowrap valign=top><tt>27</tt>..<tt>2A</tt>&nbsp; </td><td align=left>factory (temperate climate)</td></tr>
<tr><td nowrap valign=top><tt>2B</tt>..<tt>2E</tt>&nbsp; </td><td align=left>printing works</td></tr>
<tr><td nowrap valign=top><tt>2F</tt>..<tt>33</tt>&nbsp; </td><td align=left>copper ore mine
<table>
<tr><td nowrap valign=top><tt>2F</tt>&nbsp; </td><td align=left>wheel tower when not animated</td></tr>
<tr><td nowrap valign=top><tt>30</tt>&nbsp; </td><td align=left>wheel tower when animated; animation state in map_owner bits 5..0; map_owner bit 6 set = sound already generated</td></tr>
<tr><td nowrap valign=top><tt>31</tt>&nbsp; </td><td align=left>chimney</td></tr>
</table>
</td></tr>
<tr><td nowrap valign=top><tt>34</tt>..<tt>39</tt>&nbsp; </td><td align=left>steel mill</td></tr>
<tr><td nowrap valign=top><tt>3A</tt>..<tt>3B</tt>&nbsp; </td><td align=left>bank (temperate climate)</td></tr>
<tr><td nowrap valign=top><tt>3C</tt>..<tt>3F</tt>&nbsp; </td><td align=left>food processing plant</td></tr>
<tr><td nowrap valign=top><tt>40</tt>..<tt>47</tt>&nbsp; </td><td align=left>paper mill</td></tr>
<tr><td nowrap valign=top><tt>48</tt>..<tt>58</tt>&nbsp; </td><td align=left>gold mine
<table>
<tr><td nowrap valign=top><tt>4F</tt>&nbsp; </td><td align=left>wheel tower when not animated</td></tr>
<tr><td nowrap valign=top><tt>58</tt>&nbsp; </td><td align=left>wheel tower when animated; animation state in map_owner bits 5..0; map_owner bit 6 set = sound already generated</td></tr>
</table>
</td></tr>
<tr><td nowrap valign=top><tt>59</tt>..<tt>5A</tt>&nbsp; </td><td align=left>bank (sub-arctic or sub-tropical climate)</td></tr>
<tr><td nowrap valign=top><tt>5B</tt>..<tt>63</tt>&nbsp; </td><td align=left>diamond mine</td></tr>
<tr><td nowrap valign=top><tt>64</tt>..<tt>73</tt>&nbsp; </td><td align=left>iron ore mine</td></tr>
<tr><td nowrap valign=top><tt>74</tt></td><td align=left>fruit plantation</td></tr>
<tr><td nowrap valign=top><tt>75</tt></td><td align=left>rubber plantation</td></tr>
<tr><td nowrap valign=top><tt>76</tt>..<tt>77</tt>&nbsp; </td><td align=left>water supply</td></tr>
<tr><td nowrap valign=top><tt>78</tt></td><td align=left>water tower</td></tr>
<tr><td nowrap valign=top><tt>79</tt>..<tt>7C</tt>&nbsp; </td><td align=left>factory (sub-tropical climate)</td></tr>
<tr><td nowrap valign=top><tt>7D</tt>..<tt>80</tt>&nbsp; </td><td align=left>lumber mill</td></tr>
<tr><td nowrap valign=top><tt>81</tt>..<tt>82</tt>&nbsp; </td><td align=left>candyfloss forest
<table>
<tr><td nowrap valign=top><tt>82</tt>&nbsp; </td><td align=left>candyfloss 'trees' cut down</td></tr>
</table>
</td></tr>
<tr><td nowrap valign=top><tt>83</tt>..<tt>86</tt>&nbsp; </td><td align=left>sweet factory</td></tr>
<tr><td nowrap valign=top><tt>87</tt>..<tt>88</tt>&nbsp; </td><td align=left>battery farm
<table>
<tr><td nowrap valign=top><tt>88</tt>&nbsp; </td><td align=left>batteries 'reaped'</td></tr>
</table>
</td></tr>
<tr><td nowrap valign=top><tt>89</tt></td><td align=left>cola wells</td></tr>
<tr><td nowrap valign=top><tt>8A</tt>..<tt>8D</tt>&nbsp; </td><td align=left>toy shop</td></tr>
<tr><td nowrap valign=top><tt>8E</tt>..<tt>93</tt>&nbsp; </td><td align=left>toy factory
<table>
<tr><td nowrap valign=top><tt>8F</tt>&nbsp; </td><td align=left>animated part; animation state in map3_lo (valid range <tt>00</tt>..<tt>31</tt>)<br>
tile animation is started (map3_hi zeroed) on the periodic processing if <a href="#industry.didtransform">field <tt>2C</tt></a> in the corresponding industry array entry is nonzero<br>
while the animation is in progress (see the <a href="#_AnimatedTilesList">array at <tt>04328</tt></a>) map3_hi holds the number of animation cycles that have already taken place; when this number reaches 8 the animation is stopped</td></tr>
</table>
</td></tr>
<tr><td nowrap valign=top><tt>94</tt>..<tt>9B</tt>&nbsp; </td><td align=left>plastic fountains (various stages of cyclic animation)</td></tr>
<tr><td nowrap valign=top><tt>9C</tt>..<tt>9F</tt>&nbsp; </td><td align=left>fizzy drink factory</td></tr>
<tr><td nowrap valign=top><tt>A0</tt>..<tt>A3</tt>&nbsp; </td><td align=left>bubble generator
<table>
<tr><td nowrap valign=top><tt>A1</tt>&nbsp; </td><td align=left>generators</td></tr>
<tr><td nowrap valign=top><tt>A2</tt>&nbsp; </td><td align=left>bubble capture facility; animation state in map3_lo (valid range <tt>00</tt>..<tt>27</tt>)</td></tr>
</table>
</td></tr>
<tr><td nowrap valign=top><tt>A4</tt>..<tt>A6</tt>&nbsp; </td><td align=left>toffee quarry
<table>
<tr><td nowrap valign=top><tt>A5</tt>&nbsp; </td><td align=left>animated part; animation state in map3_lo (valid range <tt>00</tt>..<tt>45</tt>)</td></tr>
</table>
</td></tr>
<tr><td nowrap valign=top><tt>A7</tt>..<tt>AE</tt>&nbsp; </td><td align=left>sugar mine
<table>
<tr><td nowrap valign=top><tt>AE</tt>&nbsp; </td><td align=left>animated part; animation state in map3_lo (valid range <tt>00</tt>..<tt>5F</tt>)</td></tr>
</table>
</td></tr>
<tr><td colspan=2></td></tr> <!-- spacer -->
</table></li>
<li>map2: index into the <a href="#_IndustryArray">array of industries</a>
</li>
<li>map_owner bit 7: clear = under construction
<ul>
<li>map_owner bits 4..2: construction counter, for buildings under construction incremented on every periodic tile processing
</li>
</ul></li>
<li>map_owner bits 1..0: stage of construction (<tt>3</tt> = completed), incremented when the construction counter wraps around
<br>the meaning is different for some animated tiles which are never under construction (types <tt>01</tt>, <tt>1E</tt>..<tt>20</tt>, <tt>30</tt>, <tt>58</tt>; see above)
</li>
</ul>
</td></tr>
<tr><td valign=top nowrap><a name="Class9"><tt> 9 </tt></a></td><td>
map5 bits 7..4 clear: tunnel entrance/exit
<ul>
<li>map5 bits 3..2: <tt>0</tt> - railway tunnel, <tt>1</tt> - road tunnel</li>
<li>map5 bits 1..0 - direction: entrance towards: <tt>0</tt> = NE, <tt>1</tt> = SE, <tt>2</tt> = SW, <tt>3</tt> = NW</li>
<li>map_owner: <a href="#OwnershipInfo">owner</a> of the tunnel</li>
<li>map3_lo bits 3..0 = <a href="#TrackType">track type</a> for railway tunnel, must be 0 for road tunnel</li>
<li>map3_hi bit 7 set = on snow or desert</li>
</ul>
map5 bit 7 set: bridge
<ul><li>
map5 bit 6 clear: bridge ending
<ul>
<li>map5 bit 5: clear - northern, set - southern ending</li>
<li>map3_lo bits 3..0 = <a href="#TrackType">type of track</a> on the bridge, must be 0 for road bridge</li>
<li>map_owner: <a href="#OwnershipInfo">owner</a> of the bridge</li>
</ul>
map5 bit 6 set: bridge middle part
<ul>
<li>map5 bit 5 clear:
<ul>
<li>map5 bits 4..3: land under bridge: <tt>0</tt> - grass, snow or desert, <tt>1</tt> - water</li>
</ul>
map5 bit 5 set:
<ul>
<li>map5 bits 4..3: transport route under bridge: <tt>0</tt> - railway, <tt>1</tt> - road</li>
</ul>
<li>map3_lo bits 7..4 = <a href="#TrackType">type of track</a> on the bridge, must be 0 for road bridge</li>
<li>map3_lo bits 3..0 = <a href="#TrackType">type of track</a> under the bridge, if any</li>
<li>map2 bits 3..0: bridge piece (<tt>0</tt>..<tt>5</tt>)
<li>map_owner: <a href="#OwnershipInfo">owner</a> of the land under bridge</li>
</ul></li>
<li>map5 bits 2..1: <tt>0</tt> - railway bridge, <tt>1</tt> - road bridge</li>
<li>map5 bit 0: clear - bridge in the X direction, set - bridge in the Y direction</li>
<li>map2 bits 7..4: <a name="BridgeType">bridge type</a>:
<table>
<tr><th align=left>Type&nbsp;</th><th align=left>Max. speed (mph)&nbsp;</th><th align=left>Description</th></tr>
<tr><td nowrap valign=top><tt>0</tt>&nbsp; </td><td align=center>20</td><td align=left>wooden</td></tr>
<tr><td nowrap valign=top><tt>1</tt>&nbsp; </td><td align=center>30</td><td align=left>concrete</td></tr>
<tr><td nowrap valign=top><tt>2</tt>&nbsp; </td><td align=center>40</td><td align=left>girder, steel</td></tr>
<tr><td nowrap valign=top><tt>3</tt>&nbsp; </td><td align=center>50</td><td align=left>suspension, concrete</td></tr>
<tr><td nowrap valign=top><tt>4</tt>&nbsp; </td><td align=center>60</td><td align=left>suspension, steel</td></tr>
<tr><td nowrap valign=top><tt>5</tt>&nbsp; </td><td align=center>70</td><td align=left>suspension, steel</td></tr>
<tr><td nowrap valign=top><tt>6</tt>&nbsp; </td><td align=center>100</td><td align=left>cantilever, steel</td></tr>
<tr><td nowrap valign=top><tt>7</tt>&nbsp; </td><td align=center>130</td><td align=left>cantilever, steel</td></tr>
<tr><td nowrap valign=top><tt>8</tt>&nbsp; </td><td align=center>150</td><td align=left>cantilever, steel</td></tr>
<tr><td nowrap valign=top><tt>9</tt>&nbsp; </td><td align=center>160</td><td align=left>girder, steel</td></tr>
<tr><td nowrap valign=top><tt>A</tt>&nbsp; </td><td align=center>200</td><td align=left>tubular, steel</td></tr>
</table></li>
<li>map3_hi bit 7 set = on snow or desert</li>
</ul>
</td></tr>
<tr><td valign=top nowrap><a name="ClassA"><tt> A </tt></a></td><td>
<ul>
<li>map5: tile type:
<table>
<tr><td nowrap valign=top><tt>00</tt>&nbsp; </td><td align=left>transmitter</td></tr>
<tr><td nowrap valign=top><tt>01</tt>&nbsp; </td><td align=left>lighthouse</td></tr>
<tr><td nowrap valign=top><tt>02</tt>&nbsp; </td><td align=left>company statue</td></tr>
<tr><td nowrap valign=top><tt>03</tt>&nbsp; </td><td align=left>company-owned land</td></tr>
<tr><td nowrap valign=top><tt>80</tt>..<tt>93</tt>&nbsp; </td><td align=left>company headquarters (5 sets of 4 tiles each, updated quarterly depending on the company performance)</td></tr>
</table>
</li>
<li>map_owner: <a href="#OwnershipInfo">owner</a> of the object (for lighthouses and transmitters normally <tt>10</tt>)</li>
</ul>
</td></tr>
<tr><td colspan=2>
Classes <tt>B</tt> through <tt>F</tt> are reserved. The presence of a tile in one of the reserved classes will crash TTD.
</td></tr>
</table>
<hr>
Copyright &copy; 2003 by Marcin Grzegorczyk.<br>
Transport Tycoon and Transport Tycoon Deluxe are Copyright &copy; by Chris Sawyer. All the other trademarks are the property of their respective owners.<br>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

@ -0,0 +1,72 @@
#include "stdafx.h"
#include "ttd.h"
#include "viewport.h"
#include "command.h"
static void DrawTile_Dummy(TileInfo *ti)
{
DrawGroundSpriteAt(0x3EC, ti->x, ti->y, ti->z);
}
static uint GetSlopeZ_Dummy(TileInfo *ti) {
return GetPartialZ(ti->x&0xF, ti->y&0xF, ti->tileh) + ti->z;
}
static int32 ClearTile_Dummy(uint tile, byte flags) {
return_cmd_error(STR_0001_OFF_EDGE_OF_MAP);
}
static void GetAcceptedCargo_Dummy(uint tile, AcceptedCargo *ac)
{
/* not used */
}
static void GetTileDesc_Dummy(uint tile, TileDesc *td)
{
td->str = STR_EMPTY;
td->owner = OWNER_NONE;
}
static void AnimateTile_Dummy(uint tile)
{
/* not used */
}
static void TileLoop_Dummy(uint tile)
{
/* not used */
}
static void ClickTile_Dummy(uint tile)
{
/* not used */
}
static void ChangeTileOwner_Dummy(uint tile, byte old_player, byte new_player)
{
/* not used */
}
static uint32 GetTileTrackStatus_Dummy(uint tile, int 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 */
};

File diff suppressed because it is too large Load Diff

@ -0,0 +1,34 @@
#ifndef ECONOMY_H
#define ECONOMY_H
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;
byte from;
byte to;
} Subsidy;
VARDEF Subsidy _subsidies[MAX_PLAYERS];
Pair SetupSubsidyDecodeParam(Subsidy *s, bool mode);
void DeleteSubsidyWithIndustry(byte index);
void DeleteSubsidyWithStation(byte index);
int32 GetTransportedGoodsIncome(uint num_pieces, uint dist, byte transit_days, byte cargo_type);
uint MoveGoodsToStation(uint tile, int w, int h, int type, uint amount);
#endif /* ECONOMY_H */

@ -0,0 +1,550 @@
#include "stdafx.h"
#include "ttd.h"
#include "engine.h"
#include "table/engines.h"
#include "player.h"
#include "command.h"
#include "vehicle.h"
#include "news.h"
#include "saveload.h"
#define UPDATE_PLAYER_RAILTYPE(e,p) if ((byte)(e->railtype + 1) > p->max_railtype) p->max_railtype = e->railtype + 1;
enum {
ENGINE_AVAILABLE = 1,
ENGINE_INTRODUCING = 2,
ENGINE_PREVIEWING = 4,
};
/* This maps per-landscape cargo ids to globally unique cargo ids usable ie. in
* the custom GRF files. It is basically just a transcribed table from
* TTDPatch's newgrf.txt. */
byte _global_cargo_id[NUM_LANDSCAPE][NUM_CARGO] = {
/* LT_NORMAL */ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12 },
/* LT_HILLY */ { 0, 1, 2, 3, 4, 5, 6, 7, 28, 11, 10, 12 },
/* LT_DESERT */ { 0, 16, 2, 3, 13, 5, 6, 7, 14, 15, 10, 12 },
/* LT_CANDY */ { 0, 17, 2, 18, 19, 20, 21, 22, 23, 24, 25, 26 },
// 27 is paper in temperate climate in TTDPatch
// Following can be renumbered:
// 29 is the default cargo for the purpose of spritesets
// 30 is the purchase list image (the equivalent of 0xff) for the purpose of spritesets
};
/* These two arrays provide a reverse mapping. */
byte _local_cargo_id_ctype[NUM_CID] = {
CT_PASSENGERS, CT_COAL, CT_MAIL, CT_OIL, CT_LIVESTOCK, CT_GOODS, CT_GRAIN, CT_WOOD, // 0-7
CT_IRON_ORE, CT_STEEL, CT_VALUABLES, CT_PAPER, CT_FOOD, CT_FRUIT, CT_COPPER_ORE, CT_WATER, // 8-15
CT_RUBBER, CT_SUGAR, CT_TOYS, CT_BATTERIES, CT_CANDY, CT_TOFFEE, CT_COLA, CT_COTTON_CANDY, // 16-23
CT_BUBBLES, CT_PLASTIC, CT_FIZZY_DRINKS, CT_PAPER /* unsup. */, CT_HILLY_UNUSED // 24-28
};
/* LT'th bit is set of the particular landscape if cargo available there.
* 1: LT_NORMAL, 2: LT_HILLY, 4: LT_DESERT, 8: LT_CANDY */
byte _local_cargo_id_landscape[NUM_CID] = {
15, 3, 15, 7, 3, 7, 7, 7, 1, 1, 7, 2, 7, // 0-12
4, 4, 4, 4, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 1, 2, // 13-28
};
void ShowEnginePreviewWindow(int engine);
void DeleteCustomEngineNames()
{
uint i;
StringID old;
for(i=0; i!=TOTAL_NUM_ENGINES; i++) {
old = _engine_name_strings[i];
_engine_name_strings[i] = i + STR_8000_KIRBY_PAUL_TANK_STEAM;
DeleteName(old);
}
_vehicle_design_names &= ~1;
}
void LoadCustomEngineNames()
{
// XXX: not done */
DEBUG(misc, 1) ("LoadCustomEngineNames: not done");
}
static void SetupEngineNames()
{
uint i;
for(i=0; i!=TOTAL_NUM_ENGINES; i++)
_engine_name_strings[i] = STR_SV_EMPTY;
DeleteCustomEngineNames();
LoadCustomEngineNames();
}
static void AdjustAvailAircraft()
{
uint16 date = _date;
byte avail = 0;
if (date >= 12784) avail |= 2; // big airport
if (date < 14610 || _patches.always_small_airport) avail |= 1; // small airport
if (date >= 15706) avail |= 4; // enable heliport
if (avail != _avail_aircraft) {
_avail_aircraft = avail;
InvalidateWindow(WC_BUILD_STATION, 0);
}
}
static void CalcEngineReliability(Engine *e)
{
uint age = e->age;
if (age < e->duration_phase_1) {
uint start = e->reliability_start;
e->reliability = age * (e->reliability_max - start) / e->duration_phase_1 + start;
} else if ((age -= e->duration_phase_1) < e->duration_phase_2) {
e->reliability = e->reliability_max;
} else if ((age -= e->duration_phase_2) < e->duration_phase_3) {
uint max = e->reliability_max;
e->reliability = (int)age * (int)(e->reliability_final - max) / e->duration_phase_3 + max;
} else {
e->player_avail = _patches.never_expire_vehicles ? -1 : 0;
e->reliability = e->reliability_final;
}
}
void StartupEngines()
{
Engine *e;
const EngineInfo *ei;
uint32 r;
SetupEngineNames();
for(e=_engines, ei=_engine_info; e != endof(_engines); e++,ei++) {
e->age = 0;
e->railtype = ei->railtype_climates >> 4;
e->flags = 0;
e->player_avail = 0;
r = Random();
e->intro_date = (uint16)((r & 0x1FF) + ei->base_intro);
if (e->intro_date <= _date) {
e->age = (_date - e->intro_date) >> 5;
e->player_avail = (byte)-1;
e->flags |= ENGINE_AVAILABLE;
}
e->reliability_start = (uint16)(((r >> 16) & 0x3fff) + 0x7AE0);
r = Random();
e->reliability_max = (uint16)((r & 0x3fff) + 0xbfff);
e->reliability_final = (uint16)(((r>>16) & 0x3fff) + 0x3fff);
r = Random();
e->duration_phase_1 = (uint16)((r & 0x1F) + 7);
e->duration_phase_2 = (uint16)(((r >> 5) & 0xF) + ei->base_life * 12 - 96);
e->duration_phase_3 = (uint16)(((r >> 9) & 0x7F) + 120);
e->reliability_spd_dec = (ei->unk2&0x7F) << 2;
/* my invented flag for something that is a wagon */
if (ei->unk2 & 0x80) {
e->age = 0xFFFF;
} else {
CalcEngineReliability(e);
}
e->lifelength = ei->lifelength + _patches.extend_vehicle_life;
// prevent certain engines from ever appearing.
if (!HASBIT(ei->railtype_climates, _opt.landscape)) {
e->flags |= ENGINE_AVAILABLE;
e->player_avail = 0;
}
}
AdjustAvailAircraft();
}
uint32 _engine_refit_masks[256];
// TODO: We don't support cargo-specific wagon overrides. Pretty exotic... ;-) --pasky
struct WagonOverride {
byte *train_id;
int trains;
struct SpriteSuperSet superset;
};
static struct WagonOverrides {
int overrides_count;
struct WagonOverride *overrides;
} _engine_wagon_overrides[256];
void SetWagonOverrideSprites(byte engine, struct SpriteSuperSet *superset,
byte *train_id, int trains)
{
struct WagonOverrides *wos;
struct WagonOverride *wo;
wos = &_engine_wagon_overrides[engine];
wos->overrides_count++;
wos->overrides = realloc(wos->overrides,
wos->overrides_count * sizeof(struct WagonOverride));
wo = &wos->overrides[wos->overrides_count - 1];
wo->superset = *superset;
wo->trains = trains;
wo->train_id = malloc(trains);
memcpy(wo->train_id, train_id, trains);
}
static struct SpriteSuperSet *GetWagonOverrideSpriteSet(byte engine, byte overriding_engine)
{
struct WagonOverrides *wos = &_engine_wagon_overrides[engine];
int i;
// XXX: This could turn out to be a timesink on profiles. We could always just
// dedicate 65535 bytes for an [engine][train] trampoline.
for (i = 0; i < wos->overrides_count; i++) {
struct WagonOverride *wo = &wos->overrides[i];
int j;
for (j = 0; j < wo->trains; j++) {
if (wo->train_id[j] == overriding_engine)
return &wo->superset;
}
}
return NULL;
}
byte _engine_original_sprites[256];
// 0 - 28 are cargos, 29 is default, 30 is the advert (purchase list)
// (It isn't and shouldn't be like this in the GRF files since new cargo types
// may appear in future - however it's more convenient to store it like this in
// memory. --pasky)
static struct SpriteSuperSet _engine_custom_sprites[256][NUM_CID];
void SetCustomEngineSprites(byte engine, byte cargo, struct SpriteSuperSet *superset)
{
assert(superset->sprites_per_set == 4 || superset->sprites_per_set == 8);
_engine_custom_sprites[engine][cargo] = *superset;
}
int GetCustomEngineSprite(byte engine, uint16 overriding_engine, byte cargo,
byte loaded, byte in_motion, byte direction)
{
struct SpriteSuperSet *superset = &_engine_custom_sprites[engine][cargo];
int totalsets, spriteset;
int r;
if (overriding_engine != 0xffff) {
struct SpriteSuperSet *overset;
overset = GetWagonOverrideSpriteSet(engine, overriding_engine);
if (overset) superset = overset;
}
if (!superset->sprites_per_set && cargo != 29) {
// This superset is empty but perhaps there'll be a default one.
superset = &_engine_custom_sprites[engine][29];
}
if (!superset->sprites_per_set) {
// This superset is empty. This function users should therefore
// look up the sprite number in _engine_original_sprites.
return 0;
}
direction %= 8;
if (superset->sprites_per_set == 4)
direction %= 4;
totalsets = in_motion ? superset->loaded_count : superset->loading_count;
// My aim here is to make it possible to visually determine absolutely
// empty and totally full vehicles. --pasky
if (loaded == 100 || totalsets == 1) { // full
spriteset = totalsets - 1;
} else if (loaded == 0 || totalsets == 2) { // empty
spriteset = 0;
} else { // something inbetween
spriteset = loaded * (totalsets - 2) / 100 + 1;
// correct possible rounding errors
if (!spriteset)
spriteset = 1;
else if (spriteset == totalsets - 1)
spriteset--;
}
r = (in_motion ? superset->loaded[spriteset] : superset->loading[spriteset]) + direction;
return r;
}
static char *_engine_custom_names[256];
void SetCustomEngineName(int engine, char *name)
{
_engine_custom_names[engine] = strdup(name);
}
StringID GetCustomEngineName(int engine)
{
if (!_engine_custom_names[engine])
return _engine_name_strings[engine];
strcpy(_userstring, _engine_custom_names[engine]);
return STR_SPEC_USERSTRING;
}
void AcceptEnginePreview(Engine *e, int player)
{
Player *p;
SETBIT(e->player_avail, player);
p = DEREF_PLAYER(player);
UPDATE_PLAYER_RAILTYPE(e,p);
e->preview_player = 0xFF;
InvalidateWindowClasses(WC_BUILD_VEHICLE);
}
void EnginesDailyLoop()
{
Engine *e;
int i,num;
Player *p;
uint mask;
int32 best_hist;
int best_player;
if (_cur_year >= 130)
return;
for(e=_engines,i=0; i!=TOTAL_NUM_ENGINES; e++,i++) {
if (e->flags & ENGINE_INTRODUCING) {
if (e->flags & ENGINE_PREVIEWING) {
if (!--e->preview_wait) {
e->flags &= ~ENGINE_PREVIEWING;
DeleteWindowById(WC_ENGINE_PREVIEW, i);
e->preview_player++;
}
} else if (e->preview_player != 0xFF) {
num = e->preview_player;
mask = 0;
do {
best_hist = -1;
best_player = -1;
FOR_ALL_PLAYERS(p) {
if (p->is_active && p->block_preview == 0 && !HASBIT(mask,p->index) &&
p->old_economy[0].performance_history > best_hist) {
best_hist = p->old_economy[0].performance_history;
best_player = p->index;
}
}
if (best_player == -1) {
e->preview_player = 0xFF;
goto next_engine;
}
mask |= (1 << best_player);
} while (--num != 0);
if (!IS_HUMAN_PLAYER(best_player)) {
/* TTDBUG: TTD has a bug here */
AcceptEnginePreview(e, best_player);
} else {
e->flags |= ENGINE_PREVIEWING;
e->preview_wait = 20;
if (IS_INTERACTIVE_PLAYER(best_player)) {
ShowEnginePreviewWindow(i);
}
}
}
}
next_engine:;
}
}
int32 CmdWantEnginePreview(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
if (flags & DC_EXEC) {
AcceptEnginePreview(&_engines[p1], _current_player);
}
return 0;
}
void NewVehicleAvailable(Engine *e)
{
Vehicle *v;
Player *p;
int index = e - _engines;
// In case the player didn't build the vehicle during the intro period,
// prevent that player from getting future intro periods for a while.
if (e->flags&ENGINE_INTRODUCING) {
FOR_ALL_PLAYERS(p) {
if (!HASBIT(e->player_avail,p->index))
continue;
for(v=_vehicles;;) {
if (v->type == VEH_Train || v->type == VEH_Road || v->type == VEH_Ship ||
(v->type == VEH_Aircraft && v->subtype <= 2)) {
if (v->owner == p->index && v->engine_type == index) break;
}
if (++v == endof(_vehicles)) {
p->block_preview = 20;
break;
}
}
}
}
// Now available for all players
e->player_avail = (byte)-1;
FOR_ALL_PLAYERS(p) {
if (p->is_active)
UPDATE_PLAYER_RAILTYPE(e,p);
}
e->flags = (e->flags & ~ENGINE_INTRODUCING) | ENGINE_AVAILABLE;
if ((byte)index < NUM_TRAIN_ENGINES) {
AddNewsItem(index, NEWS_FLAGS(NM_CALLBACK, 0, NT_NEW_VEHICLES, DNC_TRAINAVAIL), 0, 0);
} else if ((byte)index < NUM_TRAIN_ENGINES + NUM_ROAD_ENGINES) {
AddNewsItem(index, NEWS_FLAGS(NM_CALLBACK, 0, NT_NEW_VEHICLES, DNC_ROADAVAIL), 0, 0);
} else if ((byte)index < NUM_TRAIN_ENGINES + NUM_ROAD_ENGINES + NUM_SHIP_ENGINES) {
AddNewsItem(index, NEWS_FLAGS(NM_CALLBACK, 0, NT_NEW_VEHICLES, DNC_SHIPAVAIL), 0, 0);
} else {
AddNewsItem(index, NEWS_FLAGS(NM_CALLBACK, 0, NT_NEW_VEHICLES, DNC_AIRCRAFTAVAIL), 0, 0);
}
InvalidateWindowClasses(WC_BUILD_VEHICLE);
}
void EnginesMonthlyLoop()
{
Engine *e;
if (_cur_year < 130) {
for(e=_engines; e != endof(_engines); e++) {
// Age the vehicle
if (e->flags&ENGINE_AVAILABLE && e->age != 0xFFFF) {
e->age++;
CalcEngineReliability(e);
}
if (!(e->flags & ENGINE_AVAILABLE) && (uint16)(_date - min(_date, 365)) >= e->intro_date) {
// Introduce it to all players
NewVehicleAvailable(e);
} else if (!(e->flags & (ENGINE_AVAILABLE|ENGINE_INTRODUCING)) && _date >= e->intro_date) {
// Introduction date has passed.. show introducing dialog to one player.
e->flags |= ENGINE_INTRODUCING;
e->preview_player = 1; // Give to the player with the highest rating.
}
}
}
AdjustAvailAircraft();
}
int32 CmdRenameEngine(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
StringID str;
str = AllocateName((byte*)_decode_parameters, 0);
if (str == 0)
return CMD_ERROR;
if (flags & DC_EXEC) {
StringID old_str = _engine_name_strings[p1];
_engine_name_strings[p1] = str;
DeleteName(old_str);
_vehicle_design_names |= 3;
MarkWholeScreenDirty();
} else {
DeleteName(str);
}
return 0;
}
int GetPlayerMaxRailtype(int p)
{
Engine *e;
int rt = 0;
int i;
for(e=_engines,i=0; i!=lengthof(_engines); e++,i++) {
if (!HASBIT(e->player_avail, p))
continue;
if ((i >= 27 && i < 54) || (i >= 57 && i < 84) || (i >= 89 && i < 116))
continue;
if (rt < e->railtype)
rt = e->railtype;
}
return rt + 1;
}
static const byte _engine_desc[] = {
SLE_VAR(Engine,intro_date, SLE_UINT16),
SLE_VAR(Engine,age, SLE_UINT16),
SLE_VAR(Engine,reliability, SLE_UINT16),
SLE_VAR(Engine,reliability_spd_dec, SLE_UINT16),
SLE_VAR(Engine,reliability_start, SLE_UINT16),
SLE_VAR(Engine,reliability_max, SLE_UINT16),
SLE_VAR(Engine,reliability_final, SLE_UINT16),
SLE_VAR(Engine,duration_phase_1, SLE_UINT16),
SLE_VAR(Engine,duration_phase_2, SLE_UINT16),
SLE_VAR(Engine,duration_phase_3, SLE_UINT16),
SLE_VAR(Engine,lifelength, SLE_UINT8),
SLE_VAR(Engine,flags, SLE_UINT8),
SLE_VAR(Engine,preview_player, SLE_UINT8),
SLE_VAR(Engine,preview_wait, SLE_UINT8),
SLE_VAR(Engine,railtype, SLE_UINT8),
SLE_VAR(Engine,player_avail, SLE_UINT8),
// reserve extra space in savegame here. (currently 16 bytes)
SLE_CONDARR(NullStruct,null,SLE_FILE_U64 | SLE_VAR_NULL, 2, 2, 255),
SLE_END()
};
static void Save_ENGN()
{
Engine *e;
int i;
for(i=0,e=_engines; i != lengthof(_engines); i++,e++) {
SlSetArrayIndex(i);
SlObject(e, _engine_desc);
}
}
static void Load_ENGN()
{
int index;
while ((index = SlIterateArray()) != -1) {
SlObject(&_engines[index], _engine_desc);
}
}
static void LoadSave_ENGS()
{
SlArray(_engine_name_strings, lengthof(_engine_name_strings), SLE_STRINGID);
}
const ChunkHandler _engine_chunk_handlers[] = {
{ 'ENGN', Save_ENGN, Load_ENGN, CH_ARRAY},
{ 'ENGS', LoadSave_ENGS, LoadSave_ENGS, CH_RIFF | CH_LAST},
};

@ -0,0 +1,137 @@
#ifndef ENGINE_H
#define ENGINE_H
typedef struct RailVehicleInfo {
byte image_index;
byte flags; /* 1=multihead engine, 2=wagon */
byte base_cost;
uint16 max_speed;
uint16 power;
byte weight;
byte running_cost_base;
byte engclass; // 0: steam, 1: diesel, 2: electric
byte capacity;
byte cargo_type;
} 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 EngineInfo {
uint16 base_intro;
byte unk2;
byte lifelength;
byte base_life;
byte railtype_climates;
} 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;
} Engine;
enum {
RVI_MULTIHEAD = 1,
RVI_WAGON = 2,
};
void StartupEngines();
struct SpriteSuperSet {
// XXX: Would anyone ever need more than 16 spritesets? Maybe we should
// use even less, now we take whole 8kb for custom sprites table, oh my!
byte sprites_per_set; // means number of directions - 4 or 8
// Loaded = in motion, loading = not moving
// Each superset contains several spritesets, for various loading stages
byte loaded_count;
uint16 loaded[16]; // sprite ids
byte loading_count;
uint16 loading[16]; // sprite ids
};
extern byte _global_cargo_id[NUM_LANDSCAPE][NUM_CARGO];
enum {
CID_DEFAULT = 29,
CID_PURCHASE = 30,
NUM_CID = 31,
};
extern byte _local_cargo_id_ctype[NUM_CID];
extern byte _local_cargo_id_landscape[NUM_CID];
extern uint32 _engine_refit_masks[256];
extern byte _engine_original_sprites[256];
void SetWagonOverrideSprites(byte engine, struct SpriteSuperSet *superset, byte *train_id, int trains);
void SetCustomEngineSprites(byte engine, byte cargo, struct SpriteSuperSet *superset);
// loaded is in percents, overriding_engine 0xffff is none
int GetCustomEngineSprite(byte engine, uint16 overriding_engine, byte cargo, byte loaded, byte in_motion, byte direction);
#define GetCustomVehicleSprite(v, direction) \
GetCustomEngineSprite(v->engine_type, v->type == VEH_Train ? v->u.rail.first_engine : -1, \
_global_cargo_id[_opt.landscape][v->cargo_type], \
((v->cargo_count + 1) * 100) / (v->cargo_cap + 1), \
!!v->cur_speed, direction);
void SetCustomEngineName(int engine, char *name);
StringID GetCustomEngineName(int engine);
void DrawTrainEngine(int x, int y, int engine, uint32 image_ormod);
void DrawRoadVehEngine(int x, int y, int engine, uint32 image_ormod);
void DrawShipEngine(int x, int y, int engine, uint32 image_ormod);
void DrawAircraftEngine(int x, int y, int engine, uint32 image_ormod);
void DrawTrainEngineInfo(int engine, int x, int y, int maxw);
void DrawRoadVehEngineInfo(int engine, int x, int y, int maxw);
void DrawShipEngineInfo(int engine, int x, int y, int maxw);
void DrawAircraftEngineInfo(int engine, int x, int y, int maxw);
void AcceptEnginePreview(Engine *e, int player);
void LoadCustomEngineNames();
void DeleteCustomEngineNames();
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_NORMAL_RAIL_ENGINES+NUM_MONORAIL_ENGINES+NUM_MAGLEV_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];
VARDEF StringID _engine_name_strings[TOTAL_NUM_ENGINES];
extern EngineInfo _engine_info[TOTAL_NUM_ENGINES];
extern RailVehicleInfo _rail_vehicle_info[];
#define ship_vehicle_info(e) _ship_vehicle_info[e - SHIP_ENGINES_INDEX]
extern ShipVehicleInfo _ship_vehicle_info[];
#endif

@ -0,0 +1,224 @@
#include "stdafx.h"
#include "ttd.h"
#include "window.h"
#include "gui.h"
#include "viewport.h"
#include "gfx.h"
#include "engine.h"
#include "command.h"
#include "news.h"
void DrawShipEngine(int x, int y, int engine, uint32 image_ormod);
void DrawShipEngineInfo(int engine, int x, int y, int maxw);
StringID GetEngineCategoryName(byte engine)
{
if (engine < NUM_NORMAL_RAIL_ENGINES)
return STR_8102_RAILROAD_LOCOMOTIVE;
if (engine < NUM_NORMAL_RAIL_ENGINES + NUM_MONORAIL_ENGINES)
return STR_8106_MONORAIL_LOCOMOTIVE;
if (engine < NUM_TRAIN_ENGINES)
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_TEXTBTN, 5, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, 5, 11, 299, 0, 13, STR_8100_MESSAGE_FROM_VEHICLE_MANUFACTURE, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_IMGBTN, 5, 0, 299, 14, 191, 0x0},
{ WWT_PUSHTXTBTN, 5, 85, 144, 172, 183, STR_00C9_NO},
{ WWT_PUSHTXTBTN, 5, 155, 214, 172, 183, STR_00C8_YES},
{ WWT_LAST},
};
typedef void DrawEngineProc(int x, int y, int engine, uint32 image_ormod);
typedef void DrawEngineInfoProc(int x, int y, int engine, int maxw);
typedef struct DrawEngineInfo {
DrawEngineProc *engine_proc;
DrawEngineInfoProc *info_proc;
} DrawEngineInfo;
static const DrawEngineInfo _draw_engine_list[4] = {
{DrawTrainEngine,DrawTrainEngineInfo},
{DrawRoadVehEngine,DrawRoadVehEngineInfo},
{DrawShipEngine,DrawShipEngineInfo},
{DrawAircraftEngine,DrawAircraftEngineInfo},
};
static void EnginePreviewWndProc(Window *w, WindowEvent *e)
{
byte eng;
int engine;
const DrawEngineInfo *dei;
int width;
switch(e->event) {
case WE_PAINT:
DrawWindowWidgets(w);
engine = w->window_number;
SET_DPARAM16(0, GetEngineCategoryName(engine));
DrawStringMultiCenter(150, 44, STR_8101_WE_HAVE_JUST_DESIGNED_A, 296);
DrawStringCentered(w->width >> 1, 80, GetCustomEngineName(engine), 0x10);
eng = (byte)engine;
(dei = _draw_engine_list,eng < NUM_TRAIN_ENGINES) ||
(dei++,eng < NUM_TRAIN_ENGINES + NUM_ROAD_ENGINES) ||
(dei++,eng < 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(int engine)
{
Window *w;
w = AllocateWindowDesc(&_engine_preview_desc);
w->window_number = engine;
}
void DrawNewsNewTrainAvail(Window *w)
{
int engine;
DrawNewsBorder(w);
engine = WP(w,news_d).ni->string_id;
SET_DPARAM16(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);
SET_DPARAM16(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, 0x4323);
DrawTrainEngineInfo(engine, w->width >> 1, 129, w->width - 52);
}
StringID GetNewsStringNewTrainAvail(NewsItem *ni)
{
int engine = ni->string_id;
SET_DPARAM16(0, STR_8859_NEW_NOW_AVAILABLE);
SET_DPARAM16(1, GetEngineCategoryName(engine));
SET_DPARAM16(2, GetCustomEngineName(engine));
return STR_02B6;
}
void DrawNewsNewAircraftAvail(Window *w)
{
int 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);
SET_DPARAM16(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, 0x4323);
DrawAircraftEngineInfo(engine, w->width >> 1, 131, w->width - 52);
}
StringID GetNewsStringNewAircraftAvail(NewsItem *ni)
{
int engine = ni->string_id;
SET_DPARAM16(0, STR_A02C_NEW_AIRCRAFT_NOW_AVAILABLE);
SET_DPARAM16(1, GetCustomEngineName(engine));
return STR_02B6;
}
void DrawNewsNewRoadVehAvail(Window *w)
{
int 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);
SET_DPARAM16(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, 0x4323);
DrawRoadVehEngineInfo(engine, w->width >> 1, 129, w->width - 52);
}
StringID GetNewsStringNewRoadVehAvail(NewsItem *ni)
{
int engine = ni->string_id;
SET_DPARAM16(0, STR_9028_NEW_ROAD_VEHICLE_NOW_AVAILABLE);
SET_DPARAM16(1, GetCustomEngineName(engine));
return STR_02B6;
}
void DrawNewsNewShipAvail(Window *w)
{
int 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);
SET_DPARAM16(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, 0x4323);
DrawShipEngineInfo(engine, w->width >> 1, 131, w->width - 52);
}
StringID GetNewsStringNewShipAvail(NewsItem *ni)
{
int engine = ni->string_id;
SET_DPARAM16(0, STR_982C_NEW_SHIP_NOW_AVAILABLE);
SET_DPARAM16(1, GetCustomEngineName(engine));
return STR_02B6;
}

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

@ -0,0 +1,123 @@
#include "stdafx.h"
#include "ttd.h"
#if defined(UNIX)
#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()
{
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()
{
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()
{
byte b = FioReadByte();
return (FioReadByte() << 8) | b;
}
uint32 FioReadDword()
{
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);
}
void FioCloseAll()
{
int i;
for(i=0; i!=lengthof(_fio.handles); i++) {
if (_fio.handles[i] != NULL) {
fclose(_fio.handles[i]);
_fio.handles[i] = NULL;
}
}
}
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");
}
#endif
if (f == NULL)
error("Cannot open file '%s'", buf);
_fio.handles[slot] = f;
FioSeekToFile(slot << 24);
}

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

@ -0,0 +1,253 @@
#ifndef FUNCTIONS_H
#define FUNCTIONS_H
/* vehicle.c */
/* window.c */
/* landscape.c */
void FindLandscapeHeight(TileInfo *ti, uint x, uint y);
void FindLandscapeHeightByTile(TileInfo *ti, uint tile);
uint GetTileSlope(uint tile, int *h);
int GetTileZ(uint tile);
void DoClearSquare(uint tile);
void CDECL ModifyTile(uint tile, uint flags, ...);
void SetMapExtraBits(uint tile, byte flags);
uint GetMapExtraBits(uint tile);
void RunTileLoop();
uint GetPartialZ(int x, int y, int corners);
uint GetSlopeZ(int x, int y);
uint32 GetTileTrackStatus(uint tile, int mode);
void GetAcceptedCargo(uint tile, AcceptedCargo *ac);
void ChangeTileOwner(uint tile, byte old_player, byte new_player);
void AnimateTile(uint tile);
void ClickTile(uint tile);
void GetTileDesc(uint tile, TileDesc *td);
void DrawTile(TileInfo *ti);
uint TileAddWrap(TileIndex tile, int add);
enum {
TILE_WRAPPED = (uint)-1
};
bool IsValidTile(uint tile);
#if !defined(NEW_ROTATION)
static Point FORCEINLINE RemapCoords(int x, int y, int z) { Point pt = { (y-x)*2, y + x -z }; return pt; }
#else
static Point FORCEINLINE RemapCoords(int x, int y, int z) { Point pt = { (x + y)*2, x - y -z }; return pt; }
#endif
static Point FORCEINLINE RemapCoords2(int x, int y) { return RemapCoords(x, y, GetSlopeZ(x, y)); }
/* game.c */
byte *GetString(byte *buffr, uint16 string);
void InjectDparam(int amount);
int32 GetParamInt32();
int GetParamInt16();
int GetParamInt8();
int GetParamUint16();
/* sound.c */
void SndPlayTileFx(int sound, TileIndex tile);
void SndPlayVehicleFx(int sound, Vehicle *v);
void SndPlayFx(int sound);
/* clear_land.c */
void DrawHillyLandTile(TileInfo *ti);
void DrawClearLandTile(TileInfo *ti, byte set);
void DrawClearLandFence(TileInfo *ti, byte img);
void TileLoopClearHelper(uint tile);
/* station_land.c */
void StationPickerDrawSprite(int x, int y, int railtype, int image);
/* track_land.c */
void DrawTrainDepotSprite(int x, int y, int image, int railtype);
/* 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(uint tile);
/* players.c */
bool CheckPlayerHasMoney(int32 cost);
void SubtractMoneyFromPlayer(int32 cost);
void SubtractMoneyFromPlayerFract(byte player, int32 cost);
bool CheckOwnership(byte owner);
bool CheckTileOwnership(uint tile);
StringID GetPlayerNameString(byte player);
/* standard */
void ShowInfo(const char *str);
void CDECL ShowInfoF(const char *str, ...);
void NORETURN CDECL error(const char *str, ...);
void memswap(void *a, void *b, size_t size);
/* ttd.c */
uint32 Random();
uint RandomRange(uint max);
uint32 InteractiveRandom(); /* Used for random sequences that are not the same on the other end of the multiplayer link */
void SetDate(uint date);
/* facedraw.c */
void DrawPlayerFace(uint32 face, int color, int x, int y);
/* texteff.c */
void MoveAllTextEffects();
void AddTextEffect(StringID msg, int x, int y, uint16 duration);
void InitTextEffects();
void DrawTextEffects(DrawPixelInfo *dpi);
bool AddAnimatedTile(uint tile);
void DeleteAnimatedTile(uint tile);
void AnimateAnimatedTiles();
void InitializeAnimatedTiles();
/* tunnelbridge_cmd.c */
bool CheckTunnelInWay(uint tile, int z);
bool CheckBridge_Stuff(byte bridge_type, int bridge_len);
uint32 GetBridgeLength(TileIndex begin, TileIndex end);
int CalcBridgeLenCostFactor(int x);
/* network.c */
typedef void CommandCallback(bool success, uint tile, uint32 p1, uint32 p2);
bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, CommandCallback *callback, uint32 cmd);
void NetworkConnect(const char *hostname, int port);
void NetworkReceive();
void NetworkSend();
void NetworkProcessCommands();
void NetworkListen(int port);
void NetworkInitialize();
void NetworkShutdown();
void NetworkSendCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback);
void NetworkStartSync();
void NetworkUDPListen(int port);
void NetworkUDPReceive();
void NetworkIPListInit();
bool NetworkUDPSearchServer();
/* misc_cmd.c */
void PlaceTreesRandomly();
uint GetTileDist(TileIndex xy1, TileIndex xy2);
uint GetTileDist1D(TileIndex xy1, TileIndex xy2);
uint GetTileDist1Db(TileIndex xy1, TileIndex xy2);
uint GetTileDistAdv(TileIndex xy1, TileIndex xy2);
bool CheckDistanceFromEdge(TileIndex tile, uint distance);
void InitializeLandscapeVariables(bool only_constants);
/* misc.c */
void DeleteName(StringID id);
byte *GetName(int id, byte *buff);
StringID AllocateName(const byte *name, byte skip);
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(byte cls, WindowNumber number);
void InvalidateWindowWidget(byte cls, WindowNumber number, byte widget_index);
void InvalidateWindowClasses(byte cls);
void DeleteWindowById(WindowClass cls, WindowNumber number);
void SetObjectToPlaceWnd(int icon, byte mode, Window *w);
void SetObjectToPlace(int icon, byte mode, byte window_class, uint16 window_num);
void ResetObjectToPlace();
bool ScrollMainWindowToTile(TileIndex tile);
bool ScrollMainWindowTo(int x, int y);
void DrawSprite(uint32 img, int x, int y);
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 MarkWholeScreenDirty();
void DrawFoundation(TileInfo *ti, uint f);
bool CheckIfAuthorityAllows(uint tile);
Town *ClosestTownFromTile(uint tile, uint threshold);
void ChangeTownRating(Town *t, int add, int max);
uint GetRoadBitsByTile(TileIndex tile);
int GetTownRadiusGroup(Town *t, uint tile);
int32 GetTransportedGoodsIncome(uint num_pieces, uint dist, byte transit_days, byte cargo_type);
void ShowRenameSignWindow(SignStruct *ss);
void ShowRenameCheckpointWindow(Checkpoint *cp);
int FindFirstBit(uint32 x);
void ShowHighscoreTable(int tbl);
TileIndex AdjustTileCoordRandomly(TileIndex a, byte rng);
enum SaveOrLoadResult {
SL_OK = 0, // completed successfully
SL_ERROR = 1, // error that was caught before internal structures were modified
SL_REINIT = 2, // error that was caught in the middle of updating game state, need to clear it. (can only happen during load)
};
enum SaveOrLoadMode {
SL_INVALID = -1,
SL_LOAD = 0,
SL_SAVE = 1,
SL_OLD_LOAD = 2,
};
int SaveOrLoad(const char *filename, int mode);
void AfterLoadTown();
void AskExitGame();
void AskExitToGameMenu();
void RedrawAutosave();
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);
void ttd_strlcpy(char *dst, const char *src, size_t len);
// callback from drivers that is called if the game size changes dynamically
void GameSizeChanged();
void ZoomInOrOutToCursor(bool in);
bool MakeScreenshot();
bool MakeWorldScreenshot(int left, int top, int width, int height, int zoom);
bool FileExists(const char *filename);
bool ReadLanguagePack(int index);
void InitializeLanguagePacks();
byte *ReadFileToMem(const char *filename, size_t *lenp, size_t maxsize);
int GetLanguageList(char **languages, int max);
const char *GetScreenshotFormatDesc(int i);
void InitializeScreenshotFormats();
void SetScreenshotFormat(int i);
void CheckSwitchToEuro();
void LoadFromConfig();
void SaveToConfig();
int ttd_main(int argc, char* argv[]);
void DeterminePaths();
char * CDECL str_fmt(const char *str, ...);
#endif /* FUNCTIONS_H */

1930
gfx.c

File diff suppressed because it is too large Load Diff

110
gfx.h

@ -0,0 +1,110 @@
#ifndef GFX_H
#define GFX_H
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 {
byte *dst_ptr;
int left, top, width, height;
int pitch;
uint16 zoom;
};
typedef struct SpriteHdr {
byte info;
byte height;
uint16 width;
int16 x_offs, y_offs;
} SpriteHdr;
assert_compile(sizeof(SpriteHdr) == 8);
typedef struct CursorVars {
Point pos, size, offs, delta;
Point draw_pos, draw_size;
uint32 sprite;
int wheel; // mouse wheel movement
const uint16 *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);
int DrawStringCentered(int x, int y, uint16 str, byte color);
int DrawString(int x, int y, uint16 str, byte color);
void DrawStringCenterUnderline(int x, int y, uint16 str, byte color);
int DoDrawString(const byte *string, int x, int y, byte color);
void DrawStringRightAligned(int x, int y, uint16 str, byte color);
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);
int GetStringWidth(const byte *str);
void LoadStringWidthTable();
void DrawStringMultiCenter(int x, int y, uint16 str, int maxw);
void DrawStringMultiLine(int x, int y, uint16 str, int maxw);
void DrawDirtyBlocks();
void SetDirtyBlocks(int left, int top, int right, int bottom);
void MarkWholeScreenDirty();
void GfxInitPalettes();
bool FillDrawPixelInfo(DrawPixelInfo *n, DrawPixelInfo *o, int left, int top, int width, int height);
/* window.c */
void DrawOverlappedWindowForAll(int left, int top, int right, int bottom);
/* spritecache.c */
byte *GetSpritePtr(uint sprite);
void GfxInitSpriteMem(byte *ptr, uint32 size);
void GfxLoadSprites();
void SetMouseCursor(uint cursor);
void SetAnimatedMouseCursor(const uint16 *table);
void CursorTick();
void DrawMouseCursor();
void ScreenSizeChanged();
void UndrawMouseCursor();
bool ChangeResInGame(int w, int h);
typedef struct {
int xoffs, yoffs;
int xsize, ysize;
} SpriteDimension;
const SpriteDimension *GetSpriteDimension(uint sprite);
/* gfx.c */
VARDEF int _stringwidth_base;
VARDEF byte _stringwidth_table[0x2A0];
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;
/* spritecache.c */
//enum { NUM_SPRITES = 0x1320 };
//enum { NUM_SPRITES = 0x1500 };
enum { NUM_SPRITES = 0x3500 }; // 1500 + space for custom GRF sets
/* tables.h */
extern byte _palettes[4][256 * 3];
VARDEF byte _cur_palette[768];
#endif

@ -0,0 +1,857 @@
#include "stdafx.h"
#include "ttd.h"
#include "window.h"
#include "gui.h"
#include "gfx.h"
#include "player.h"
static uint _legend_showbits;
static uint _legend_cargobits;
/************************/
/* GENERIC GRAPH DRAWER */
/************************/
typedef struct GraphDrawer {
uint sel;
byte num_dataset;
byte num_on_x_axis;
byte month;
byte year;
bool include_neg;
byte num_vert_lines;
uint16 unk61A;
uint16 unk61C;
int left, top;
uint height;
StringID format_str_y_axis;
byte color_3, color_2, bg_line_color;
byte colors[16];
uint32 cost[16][24];
} GraphDrawer;
void DrawGraph(GraphDrawer *gw)
{
int i,j,k;
int x,y,old_x,old_y;
int color;
int right, bottom;
int num_x, num_dataset;
uint32 *row_ptr, *col_ptr;
int32 mx;
int adj_height;
uint32 y_scaling, tmp;
int32 value;
int32 cur_val;
uint sel;
color = _color_list[gw->bg_line_color].window_color_1b;
/* draw the vertical lines */
i = gw->num_vert_lines; assert(i > 0);
x = gw->left + 66;
bottom = gw->top + gw->height - 1;
do {
GfxFillRect(x, gw->top, x, bottom, color);
x += 22;
} while (--i);
/* draw the horizontal lines */
i = 9;
x = gw->left + 44;
y = gw->height + gw->top;
right = gw->left + 44 + gw->num_vert_lines*22-1;
do {
GfxFillRect(x, y, right, y, color);
y -= gw->height >> 3;
} while (--i);
/* draw vertical edge line */
GfxFillRect(x, gw->top, x, bottom, gw->color_2);
adj_height = gw->height;
if (gw->include_neg) adj_height >>= 1;
/* draw horiz edge line */
y = adj_height + gw->top;
GfxFillRect(x, y, right, y, gw->color_2);
/* find the max element */
if (gw->num_on_x_axis == 0)
return;
num_dataset = gw->num_dataset;assert(num_dataset > 0);
row_ptr = gw->cost[0];
mx = 0;
do {
num_x = gw->num_on_x_axis;assert(num_x > 0);
col_ptr = row_ptr;
do {
if (*col_ptr != 0x80000000) {
mx = max(mx, myabs(*col_ptr));
}
} while (col_ptr++, --num_x);
} while (row_ptr+=24, --num_dataset);
/* setup scaling */
y_scaling = 0x80000000;
value = adj_height * 2;
if (mx > value) {
mx = (mx + 7) & ~7;
y_scaling = (uint32) (((uint64) (value>>1) << 32) / mx);
value = mx;
}
/* draw text strings on the y axis */
tmp = value;
if (gw->include_neg) tmp >>= 1;
x = gw->left + 45;
y = gw->top - 3;
i = 9;
do {
SET_DPARAM16(0, gw->format_str_y_axis);
SET_DPARAM32(1, tmp);
tmp -= (value >> 3);
DrawStringRightAligned(x, y, STR_0170, gw->color_3);
y += gw->height >> 3;
} while (--i);
/* draw strings on the x axis */
if (gw->month != 0xFF) {
x = gw->left + 44;
y = gw->top + gw->height + 1;
j = gw->month;
k = gw->year + 1920;
i = gw->num_on_x_axis;assert(i>0);
do {
SET_DPARAM16(2, k);
SET_DPARAM16(0, j + STR_0162_JAN);
SET_DPARAM16(1, j + STR_0162_JAN + 2);
DrawString(x, y, j == 0 ? STR_016F : STR_016E, gw->color_3);
j += 3;
if (j >= 12) {
j = 0;
k++;
}
x += 22;
} while (--i);
} else {
x = gw->left + 52;
y = gw->top + gw->height + 1;
j = gw->unk61A;
i = gw->num_on_x_axis;assert(i>0);
do {
SET_DPARAM16(0, j);
DrawString(x, y, STR_01CB, gw->color_3);
j += gw->unk61C;
x += 22;
} while (--i);
}
/* draw lines and dots */
i = 0;
row_ptr = gw->cost[0];
sel = gw->sel;
do {
if (!(sel & 1)) {
x = gw->left + 55;
j = gw->num_on_x_axis;assert(j>0);
col_ptr = row_ptr;
color = gw->colors[i];
old_y = old_x = 0x80000000;
do {
cur_val = *col_ptr++;
if (cur_val != (int32)0x80000000) {
y = adj_height - BIGMULSS(cur_val, y_scaling >> 1, 31) + gw->top;
GfxFillRect(x-1, y-1, x+1, y+1, color);
if (old_x != 0x80000000)
GfxDrawLine(old_x, old_y, x, y, color);
old_x = x;
old_y = y;
} else {
old_x = 0x80000000;
}
} while (x+=22,--j);
}
} while (sel>>=1,row_ptr+=24, ++i < gw->num_dataset);
}
/****************/
/* GRAPH LEGEND */
/****************/
void DrawPlayerIcon(int p, int x, int y)
{
DrawSprite(SPRITE_PALETTE(PLAYER_SPRITE_COLOR(p) + 0x2EB), x, y);
}
static void GraphLegendWndProc(Window *w, WindowEvent *e)
{
Player *p;
switch(e->event) {
case WE_PAINT:
FOR_ALL_PLAYERS(p) {
if (!p->is_active)
SETBIT(_legend_showbits, p->index);
}
w->click_state = ((~_legend_showbits) << 3);
DrawWindowWidgets(w);
FOR_ALL_PLAYERS(p) {
if (!p->is_active)
continue;
DrawPlayerIcon(p->index, 4, 18+p->index*12);
SET_DPARAM16(0, p->name_1);
SET_DPARAM32(1, p->name_2);
SET_DPARAM16(2, GetPlayerNameString(p->index));
DrawString(21,17+p->index*12,STR_7021,HASBIT(_legend_showbits, p->index) ? 0x10 : 0xC);
}
break;
case WE_CLICK:
if (IS_INT_INSIDE(e->click.widget, 3, 11)) {
_legend_showbits ^= (1 << (e->click.widget-3));
SetWindowDirty(w);
InvalidateWindow(WC_INCOME_GRAPH, 0);
InvalidateWindow(WC_OPERATING_PROFIT, 0);
InvalidateWindow(WC_DELIVERED_CARGO, 0);
InvalidateWindow(WC_PERFORMANCE_HISTORY, 0);
}
break;
}
}
static const Widget _graph_legend_widgets[] = {
{ WWT_TEXTBTN, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, 14, 11, 249, 0, 13, STR_704E_KEY_TO_COMPANY_GRAPHS, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_IMGBTN, 14, 0, 249, 14, 113, 0x0},
{ WWT_IMGBTN, 14, 2, 247, 16, 27, 0x0,STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
{ WWT_IMGBTN, 14, 2, 247, 28, 39, 0x0,STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
{ WWT_IMGBTN, 14, 2, 247, 40, 51, 0x0,STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
{ WWT_IMGBTN, 14, 2, 247, 52, 63, 0x0,STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
{ WWT_IMGBTN, 14, 2, 247, 64, 75, 0x0,STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
{ WWT_IMGBTN, 14, 2, 247, 76, 87, 0x0,STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
{ WWT_IMGBTN, 14, 2, 247, 88, 99, 0x0,STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
{ WWT_IMGBTN, 14, 2, 247, 100, 111, 0x0,STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
{ WWT_LAST},
};
static const WindowDesc _graph_legend_desc = {
-1, -1, 250, 114,
WC_GRAPH_LEGEND,0,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
_graph_legend_widgets,
GraphLegendWndProc
};
static void ShowGraphLegend()
{
AllocateWindowDescFront(&_graph_legend_desc, 0);
}
/********************/
/* OPERATING PROFIT */
/********************/
static void SetupGraphDrawerForPlayers(GraphDrawer *gd)
{
Player *p;
uint showbits = _legend_showbits;
int nums;
int mo,yr;
// Exclude the players which aren't valid
FOR_ALL_PLAYERS(p) {
if (!p->is_active) CLRBIT(showbits,p->index);
}
gd->sel = showbits;
gd->num_vert_lines = 24;
nums = 0;
FOR_ALL_PLAYERS(p) {
if (p->is_active) nums = max(nums,p->num_valid_stat_ent);
}
gd->num_on_x_axis = min(nums,24);
mo = (_cur_month/3-nums)*3;
yr = _cur_year;
while (mo < 0) {
yr--;
mo += 12;
}
gd->year = yr;
gd->month = mo;
}
static void OperatingProfitWndProc(Window *w, WindowEvent *e)
{
switch(e->event) {
case WE_PAINT: {
GraphDrawer gd;
Player *p;
int i,j;
int numd;
DrawWindowWidgets(w);
gd.left = 2;
gd.top = 18;
gd.height = 136;
gd.include_neg = true;
gd.format_str_y_axis = STR_7023;
gd.color_3 = 0x10;
gd.color_2 = 0xD7;
gd.bg_line_color = 0xE;
SetupGraphDrawerForPlayers(&gd);
numd = 0;
FOR_ALL_PLAYERS(p) {
if (!p->is_active)
continue;
gd.colors[numd] = _color_list[p->player_color].window_color_bgb;
for(j=gd.num_on_x_axis,i=0; --j >= 0;) {
gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? 0x80000000 : (p->old_economy[j].income + p->old_economy[j].expenses);
i++;
}
numd++;
}
gd.num_dataset=numd;
DrawGraph(&gd);
break;
}
case WE_CLICK:
if (e->click.widget == 2)
ShowGraphLegend();
break;
}
}
static const Widget _operating_profit_widgets[] = {
{ WWT_TEXTBTN, 14, 0, 10, 0, 13, STR_00C5,STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, 14, 11, 525, 0, 13, STR_7025_OPERATING_PROFIT_GRAPH, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PUSHTXTBTN, 14, 526, 575, 0, 13, STR_704C_KEY, STR_704D_SHOW_KEY_TO_GRAPHS},
{ WWT_IMGBTN, 14, 0, 575, 14, 173, 0x0},
{ WWT_LAST},
};
static const WindowDesc _operating_profit_desc = {
-1, -1, 576, 174,
WC_OPERATING_PROFIT,0,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
_operating_profit_widgets,
OperatingProfitWndProc
};
void ShowOperatingProfitGraph()
{
if (AllocateWindowDescFront(&_operating_profit_desc, 0)) {
InvalidateWindow(WC_GRAPH_LEGEND, 0);
_legend_showbits = 0;
}
}
/****************/
/* INCOME GRAPH */
/****************/
static void IncomeGraphWndProc(Window *w, WindowEvent *e)
{
switch(e->event) {
case WE_PAINT: {
GraphDrawer gd;
Player *p;
int i,j;
int numd;
DrawWindowWidgets(w);
gd.left = 2;
gd.top = 18;
gd.height = 104;
gd.include_neg = false;
gd.format_str_y_axis = STR_7023;
gd.color_3 = 0x10;
gd.color_2 = 0xD7;
gd.bg_line_color = 0xE;
SetupGraphDrawerForPlayers(&gd);
numd = 0;
FOR_ALL_PLAYERS(p) {
if (!p->is_active)
continue;
gd.colors[numd] = _color_list[p->player_color].window_color_bgb;
for(j=gd.num_on_x_axis,i=0; --j >= 0;) {
gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? 0x80000000 : (p->old_economy[j].income);
i++;
}
numd++;
}
gd.num_dataset = numd;
DrawGraph(&gd);
break;
}
case WE_CLICK:
if (e->click.widget == 2)
ShowGraphLegend();
break;
}
}
static const Widget _income_graph_widgets[] = {
{ WWT_TEXTBTN, 14, 0, 10, 0, 13, STR_00C5,STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, 14, 11, 525, 0, 13, STR_7022_INCOME_GRAPH, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PUSHTXTBTN, 14, 526, 575, 0, 13, STR_704C_KEY, STR_704D_SHOW_KEY_TO_GRAPHS},
{ WWT_IMGBTN, 14, 0, 575, 14, 141, 0x0},
{ WWT_LAST},
};
static const WindowDesc _income_graph_desc = {
-1, -1, 576, 142,
WC_INCOME_GRAPH,0,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
_income_graph_widgets,
IncomeGraphWndProc
};
void ShowIncomeGraph()
{
if (AllocateWindowDescFront(&_income_graph_desc, 0)) {
InvalidateWindow(WC_GRAPH_LEGEND, 0);
_legend_showbits = 0;
}
}
/*******************/
/* DELIVERED CARGO */
/*******************/
static void DeliveredCargoGraphWndProc(Window *w, WindowEvent *e)
{
switch(e->event) {
case WE_PAINT: {
GraphDrawer gd;
Player *p;
int i,j;
int numd;
DrawWindowWidgets(w);
gd.left = 2;
gd.top = 18;
gd.height = 104;
gd.include_neg = false;
gd.format_str_y_axis = STR_7024;
gd.color_3 = 0x10;
gd.color_2 = 0xD7;
gd.bg_line_color = 0xE;
SetupGraphDrawerForPlayers(&gd);
numd = 0;
FOR_ALL_PLAYERS(p) {
if (!p->is_active)
continue;
gd.colors[numd] = _color_list[p->player_color].window_color_bgb;
for(j=gd.num_on_x_axis,i=0; --j >= 0;) {
gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? 0x80000000 : p->old_economy[j].delivered_cargo;
i++;
}
numd++;
}
gd.num_dataset = numd;
DrawGraph(&gd);
break;
}
case WE_CLICK:
if (e->click.widget == 2)
ShowGraphLegend();
break;
}
}
static const Widget _delivered_cargo_graph_widgets[] = {
{ WWT_TEXTBTN, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, 14, 11, 525, 0, 13, STR_7050_UNITS_OF_CARGO_DELIVERED, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PUSHTXTBTN, 14, 526, 575, 0, 13, STR_704C_KEY, STR_704D_SHOW_KEY_TO_GRAPHS},
{ WWT_IMGBTN, 14, 0, 575, 14, 141, 0x0},
{ WWT_LAST},
};
static const WindowDesc _delivered_cargo_graph_desc = {
-1, -1, 576, 142,
WC_DELIVERED_CARGO,0,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
_delivered_cargo_graph_widgets,
DeliveredCargoGraphWndProc
};
void ShowDeliveredCargoGraph()
{
if (AllocateWindowDescFront(&_delivered_cargo_graph_desc, 0)) {
InvalidateWindow(WC_GRAPH_LEGEND, 0);
_legend_showbits = 0;
}
}
/***********************/
/* PERFORMANCE HISTORY */
/***********************/
static void PerformanceHistoryWndProc(Window *w, WindowEvent *e)
{
switch(e->event) {
case WE_PAINT: {
GraphDrawer gd;
Player *p;
int i,j;
int numd;
DrawWindowWidgets(w);
gd.left = 2;
gd.top = 18;
gd.height = 200;
gd.include_neg = false;
gd.format_str_y_axis = STR_7024;
gd.color_3 = 0x10;
gd.color_2 = 0xD7;
gd.bg_line_color = 0xE;
SetupGraphDrawerForPlayers(&gd);
numd = 0;
FOR_ALL_PLAYERS(p) {
if (!p->is_active)
continue;
gd.colors[numd] = _color_list[p->player_color].window_color_bgb;
for(j=gd.num_on_x_axis,i=0; --j >= 0;) {
gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? 0x80000000 : p->old_economy[j].performance_history;
i++;
}
numd++;
}
gd.num_dataset = numd;
DrawGraph(&gd);
break;
}
case WE_CLICK:
if (e->click.widget == 2)
ShowGraphLegend();
break;
}
}
static const Widget _performance_history_widgets[] = {
{ WWT_TEXTBTN, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, 14, 11, 525, 0, 13, STR_7051_COMPANY_PERFORMANCE_RATINGS, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PUSHTXTBTN, 14, 526, 575, 0, 13, STR_704C_KEY, STR_704D_SHOW_KEY_TO_GRAPHS},
{ WWT_IMGBTN, 14, 0, 575, 14, 237, 0x0},
{ WWT_LAST},
};
static const WindowDesc _performance_history_desc = {
-1, -1, 576, 238,
WC_PERFORMANCE_HISTORY,0,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
_performance_history_widgets,
PerformanceHistoryWndProc
};
void ShowPerformanceHistoryGraph()
{
if (AllocateWindowDescFront(&_performance_history_desc, 0)) {
InvalidateWindow(WC_GRAPH_LEGEND, 0);
_legend_showbits = 0;
}
}
/*****************/
/* COMPANY VALUE */
/*****************/
static void CompanyValueGraphWndProc(Window *w, WindowEvent *e)
{
switch(e->event) {
case WE_PAINT: {
GraphDrawer gd;
Player *p;
int i,j;
int numd;
DrawWindowWidgets(w);
gd.left = 2;
gd.top = 18;
gd.height = 200;
gd.include_neg = false;
gd.format_str_y_axis = STR_7023;
gd.color_3 = 0x10;
gd.color_2 = 0xD7;
gd.bg_line_color = 0xE;
SetupGraphDrawerForPlayers(&gd);
numd = 0;
FOR_ALL_PLAYERS(p) {
if (!p->is_active)
continue;
gd.colors[numd] = _color_list[p->player_color].window_color_bgb;
for(j=gd.num_on_x_axis,i=0; --j >= 0;) {
gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? 0x80000000 : (p->old_economy[j].company_value);
i++;
}
numd++;
}
gd.num_dataset = numd;
DrawGraph(&gd);
break;
}
case WE_CLICK:
if (e->click.widget == 2)
ShowGraphLegend();
break;
}
}
static const Widget _company_value_graph_widgets[] = {
{ WWT_TEXTBTN, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, 14, 11, 525, 0, 13, STR_7052_COMPANY_VALUES, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PUSHTXTBTN, 14, 526, 575, 0, 13, STR_704C_KEY, STR_704D_SHOW_KEY_TO_GRAPHS},
{ WWT_IMGBTN, 14, 0, 575, 14, 237, 0x0},
{ WWT_LAST},
};
static const WindowDesc _company_value_graph_desc = {
-1, -1, 576, 238,
WC_COMPANY_VALUE,0,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
_company_value_graph_widgets,
CompanyValueGraphWndProc
};
void ShowCompanyValueGraph()
{
if (AllocateWindowDescFront(&_company_value_graph_desc, 0)) {
InvalidateWindow(WC_GRAPH_LEGEND, 0);
_legend_showbits = 0;
}
}
/*****************/
/* PAYMENT RATES */
/*****************/
static const byte _cargo_legend_colors[12] = {152, 32, 15, 174, 208, 194, 191, 84, 184, 10, 202, 215};
static void CargoPaymentRatesWndProc(Window *w, WindowEvent *e)
{
switch(e->event) {
case WE_PAINT: {
int i, j, x, y;
GraphDrawer gd;
gd.sel = _legend_cargobits;
w->click_state = (~_legend_cargobits) << 3;
DrawWindowWidgets(w);
x = 495;
y = 25;
for(i=0; i!=NUM_CARGO; i++) {
GfxFillRect(x, y, x+8, y+5, 0);
GfxFillRect(x+1, y+1, x+7, y+4, _cargo_legend_colors[i]);
SET_DPARAM16(0, _cargoc.names_s[i]);
DrawString(x+14, y, STR_7065, 0);
y += 8;
}
gd.left = 2;
gd.top = 24;
gd.height = 104;
gd.include_neg = false;
gd.format_str_y_axis = STR_7023;
gd.color_3 = 16;
gd.color_2 = 215;
gd.bg_line_color = 14;
gd.num_dataset = 12;
gd.num_on_x_axis = 20;
gd.num_vert_lines = 20;
gd.month = 0xFF;
gd.unk61A = 10;
gd.unk61C = 10;
for(i=0; i!=NUM_CARGO; i++) {
gd.colors[i] = _cargo_legend_colors[i];
for(j=0; j!=20; j++) {
gd.cost[i][j] = GetTransportedGoodsIncome(10, 20, j*6+6,i);
}
}
DrawGraph(&gd);
DrawString(2 + 46, 24 + gd.height + 7, STR_7062_DAYS_IN_TRANSIT, 0);
DrawString(2 + 84, 24 - 9, STR_7063_PAYMENT_FOR_DELIVERING, 0);
} break;
case WE_CLICK: {
switch(e->click.widget) {
case 3: case 4: case 5: case 6:
case 7: case 8: case 9: case 10:
case 11: case 12: case 13: case 14:
_legend_cargobits ^= 1 << (e->click.widget - 3);
SetWindowDirty(w);
break;
}
} break;
}
}
static const Widget _cargo_payment_rates_widgets[] = {
{ WWT_CLOSEBOX, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, 14, 11, 567, 0, 13, STR_7061_CARGO_PAYMENT_RATES, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PANEL, 14, 0, 567, 14, 141, 0x0, 0},
{ WWT_PANEL, 12, 493, 562, 24, 31, 0x0, STR_7064_TOGGLE_GRAPH_FOR_CARGO},
{ WWT_PANEL, 12, 493, 562, 32, 39, 0x0, STR_7064_TOGGLE_GRAPH_FOR_CARGO},
{ WWT_PANEL, 12, 493, 562, 40, 47, 0x0, STR_7064_TOGGLE_GRAPH_FOR_CARGO},
{ WWT_PANEL, 12, 493, 562, 48, 55, 0x0, STR_7064_TOGGLE_GRAPH_FOR_CARGO},
{ WWT_PANEL, 12, 493, 562, 56, 63, 0x0, STR_7064_TOGGLE_GRAPH_FOR_CARGO},
{ WWT_PANEL, 12, 493, 562, 64, 71, 0x0, STR_7064_TOGGLE_GRAPH_FOR_CARGO},
{ WWT_PANEL, 12, 493, 562, 72, 79, 0x0, STR_7064_TOGGLE_GRAPH_FOR_CARGO},
{ WWT_PANEL, 12, 493, 562, 80, 87, 0x0, STR_7064_TOGGLE_GRAPH_FOR_CARGO},
{ WWT_PANEL, 12, 493, 562, 88, 95, 0x0, STR_7064_TOGGLE_GRAPH_FOR_CARGO},
{ WWT_PANEL, 12, 493, 562, 96, 103, 0x0, STR_7064_TOGGLE_GRAPH_FOR_CARGO},
{ WWT_PANEL, 12, 493, 562, 104, 111, 0x0, STR_7064_TOGGLE_GRAPH_FOR_CARGO},
{ WWT_PANEL, 12, 493, 562, 112, 119, 0x0, STR_7064_TOGGLE_GRAPH_FOR_CARGO},
{ WWT_LAST},
};
static const WindowDesc _cargo_payment_rates_desc = {
-1, -1, 568, 142,
WC_PAYMENT_RATES,0,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
_cargo_payment_rates_widgets,
CargoPaymentRatesWndProc
};
void ShowCargoPaymentRates()
{
AllocateWindowDescFront(&_cargo_payment_rates_desc, 0);
}
/************************/
/* COMPANY LEAGUE TABLE */
/************************/
static const StringID _performance_titles[] = {
STR_7066_ENGINEER,
STR_7066_ENGINEER,
STR_7067_TRAFFIC_MANAGER,
STR_7067_TRAFFIC_MANAGER,
STR_7068_TRANSPORT_COORDINATOR,
STR_7068_TRANSPORT_COORDINATOR,
STR_7069_ROUTE_SUPERVISOR,
STR_7069_ROUTE_SUPERVISOR,
STR_706A_DIRECTOR,
STR_706A_DIRECTOR,
STR_706B_CHIEF_EXECUTIVE,
STR_706B_CHIEF_EXECUTIVE,
STR_706C_CHAIRMAN,
STR_706C_CHAIRMAN,
STR_706D_PRESIDENT,
STR_706E_TYCOON,
};
static StringID GetPerformanceTitleFromValue(uint v)
{
return _performance_titles[minu(v, 1000) >> 6];
}
static int CDECL _perf_hist_comp(const void *elem1, const void *elem2 ) {
Player *p1 = *(Player**)elem1;
Player *p2 = *(Player**)elem2;
int32 v = p2->old_economy[1].performance_history - p1->old_economy[1].performance_history;
return (v!=0) | (v >> (sizeof(int32)*8-1));
}
static void CompanyLeagueWndProc(Window *w, WindowEvent *e)
{
switch(e->event) {
case WE_PAINT: {
Player *p;
Player *plist[MAX_PLAYERS];
size_t pl_num, i;
DrawWindowWidgets(w);
pl_num=0;
FOR_ALL_PLAYERS(p) {
if (p->is_active)
plist[pl_num++] = p;
}
assert(pl_num > 0);
qsort(plist, pl_num, sizeof(Player*), _perf_hist_comp);
i = 0;
do {
SET_DPARAM16(0, i + 1 + STR_01AB);
p = plist[i];
SET_DPARAM16(1, p->name_1);
SET_DPARAM32(2, p->name_2);
SET_DPARAM16(3, GetPlayerNameString(p->index));
SET_DPARAM16(4, GetPerformanceTitleFromValue(p->old_economy[1].performance_history));
DrawString(2, 15 + i * 10, i == 0 ? STR_7054 : STR_7055, 0);
DrawPlayerIcon(p->index, 27, 16 + i * 10);
} while (++i != pl_num);
break;
}
}
}
static const Widget _company_league_widgets[] = {
{ WWT_TEXTBTN, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, 14, 11, 399, 0, 13, STR_7053_COMPANY_LEAGUE_TABLE, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_IMGBTN, 14, 0, 399, 14, 96, 0x0},
{ WWT_LAST},
};
static const WindowDesc _company_league_desc = {
-1, -1, 400, 97,
WC_COMPANY_LEAGUE,0,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
_company_league_widgets,
CompanyLeagueWndProc
};
void ShowCompanyLeagueTable()
{
AllocateWindowDescFront(&_company_league_desc,0);
}

File diff suppressed because it is too large Load Diff

118
gui.h

@ -0,0 +1,118 @@
#ifndef GUI_H
#define GUI_H
/* main_gui.c */
void SetupColorsAndInitialWindow();
void CcPlaySound10(bool success, uint tile, uint32 p1, uint32 p2);
void PlaceProc_Sign(uint tile);
/* settings_gui.c */
void ShowGameOptions();
void ShowGameDifficulty();
void ShowPatchesSelection();
/* graph_gui.c */
void ShowOperatingProfitGraph();
void ShowIncomeGraph();
void ShowDeliveredCargoGraph();
void ShowPerformanceHistoryGraph();
void ShowCompanyValueGraph();
void ShowCargoPaymentRates();
void ShowCompanyLeagueTable();
/* news_gui.c */
void ShowLastNewsMessage();
void ShowMessageOptions();
void ShowMessageHistory();
/* traintoolb_gui.c */
void ShowBuildRailToolbar(int index, int button);
void PlaceProc_BuyLand(uint tile);
/* train_gui.c */
void ShowPlayerTrains(int player);
void ShowTrainViewWindow(Vehicle *v);
void ShowTrainDetailsWindow(Vehicle *v);
void ShowOrdersWindow(Vehicle *v);
void ShowRoadVehViewWindow(Vehicle *v);
/* road_gui.c */
void ShowBuildRoadToolbar();
void ShowBuildRoadScenToolbar();
void ShowPlayerRoadVehicles(int player);
/* dock_gui.c */
void ShowBuildDocksToolbar();
void ShowPlayerShips(int player);
void ShowShipViewWindow(Vehicle *v);
/* aircraft_gui.c */
void ShowBuildAirToolbar();
void ShowPlayerAircraft(int player);
/* terraform_gui.c */
void PlaceProc_DemolishArea(uint tile);
void PlaceProc_LowerLand(uint tile);
void PlaceProc_RaiseLand(uint tile);
void PlaceProc_LevelLand(uint tile);
void ShowTerraformToolbar();
/* misc_gui.c */
void PlaceLandBlockInfo();
void ShowAboutWindow();
void ShowBuildTreesToolbar();
void ShowBuildTreesScenToolbar();
void ShowTownDirectory();
void ShowIndustryDirectory();
void ShowSubsidiesList();
void ShowPlayerStations(int player);
void ShowPlayerFinances(int player);
void ShowPlayerCompany(int player);
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);
void CheckRedrawStationCoverage(Window *w);
void ShowSmallMap();
void SetVScrollCount(Window *w, int num);
void SetHScrollCount(Window *w, int num);
void ShowCheatWindow();
void AskForNewGameToStart();
void DrawEditBox(Window *w, int wid);
void HandleEditBox(Window *w, int wid);
/* network gui */
void ShowNetworkGameWindow();
/* 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 DoZoomInOut(int how);
void ShowBuildIndustryWindow();
void ShowQueryString(StringID str, StringID caption, int maxlen, int maxwidth, byte window_class, uint16 window_number);
void ShowMusicWindow();
void DrawVehicleProfitButton(Vehicle *v, int x, int y);
/* main_gui.c */
VARDEF byte _newspaper_flag;
VARDEF byte _construct_mode;
VARDEF byte _station_show_coverage;
VARDEF PlaceProc *_place_proc;
VARDEF bool _no_button_sound;
#endif /* GUI_H */

146
hal.h

@ -0,0 +1,146 @@
#ifndef HAL_H
#define HAL_H
typedef struct {
char *(*start)(char **parm);
void (*stop)();
} HalCommonDriver;
typedef struct {
const char *(*start)(char **parm);
void (*stop)();
void (*make_dirty)(int left, int top, int width, int height);
int (*main_loop)();
bool (*change_resolution)(int w, int h);
} HalVideoDriver;
enum {
ML_QUIT = 0,
ML_SWITCHDRIVER = 1,
};
typedef struct {
char *(*start)(char **parm);
void (*stop)();
} HalSoundDriver;
typedef struct {
char *(*start)(char **parm);
void (*stop)();
void (*play_song)(const char *filename);
void (*stop_song)();
bool (*is_song_playing)();
void (*set_volume)(byte vol);
} HalMusicDriver;
typedef struct {
const char *name;
const char *longname;
const void *drv;
uint flags;
} DriverDesc;
enum {
HALERR_OK = 0,
HALERR_ERROR = 1,
};
extern const HalMusicDriver _null_music_driver;
extern const HalVideoDriver _null_video_driver;
extern const HalSoundDriver _null_sound_driver;
VARDEF HalMusicDriver *_music_driver;
VARDEF HalSoundDriver *_sound_driver;
VARDEF HalVideoDriver *_video_driver;
extern const DriverDesc _video_driver_descs[];
extern const DriverDesc _sound_driver_descs[];
extern const DriverDesc _music_driver_descs[];
#if defined(WITH_SDL)
extern const HalSoundDriver _sdl_sound_driver;
extern const HalVideoDriver _sdl_video_driver;
#endif
#if defined(UNIX)
extern const HalMusicDriver _extmidi_music_driver;
#endif
#if defined(__BEOS__)
extern const HalMusicDriver _bemidi_music_driver;
#endif
enum DriverType {
VIDEO_DRIVER = 0,
SOUND_DRIVER = 1,
MUSIC_DRIVER = 2,
};
extern void GameLoop();
extern bool _dbg_screen_rect;
void LoadDriver(int driver, const char *name);
char *GetDriverParam(char **parm, const char *name);
bool GetDriverParamBool(char **parm, const char *name);
int GetDriverParamInt(char **parm, const char *name, int def);
// Deals with finding savegames
typedef struct {
uint16 id;
byte type;
uint64 mtime;
char title[64];
char name[256-12-64];
int old_extension;
} FiosItem;
// extensions of old savegames, scenarios
static const char* const _old_extensions[] = {
// old savegame types
"ss1", // Transport Tycoon Deluxe preset game
"sv1", // Transport Tycoon Deluxe (Patch) saved game
"sv2", // Transport Tycoon Deluxe (Patch) saved 2-player game
// old scenario game type
"sv0", // Transport Tycoon Deluxe (Patch) scenario
"ss0", // Transport Tycoon Deluxe preset scenario
};
enum {
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,
};
// 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();
// Browse to. Returns a filename w/path if we reached a file.
char *FiosBrowseTo(const FiosItem *item);
// Get descriptive texts.
// Returns a path as well as a
// string describing the path.
StringID FiosGetDescText(char **path);
// Delete a name
void FiosDelete(const char *name);
// Make a filename from a name
void FiosMakeSavegameName(char *buf, const char *name);
void CreateConsole();
#endif /* HAL_H */

@ -0,0 +1,74 @@
#ifndef INDUSTRY_H
#define INDUSTRY_H
struct Industry {
TileIndex xy;
byte width; /* swapped order of w/h with town */
byte height;
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;
};
VARDEF int _total_industries; // For the AI: the amount of industries active
VARDEF Industry _industries[90];
#define DEREF_INDUSTRY(i) (&_industries[i])
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

File diff suppressed because it is too large Load Diff

@ -0,0 +1,590 @@
#include "stdafx.h"
#include "ttd.h"
//#include "gui.h"
#include "window.h"
#include "gfx.h"
#include "command.h"
#include "viewport.h"
#include "industry.h"
#include "town.h"
static const byte _build_industry_types[4][12] = {
{ 1, 2, 4, 6, 8, 0, 3, 5, 9, 11, 18 },
{ 1, 14, 4, 13, 7, 0, 3, 9, 11, 15 },
{ 25, 13, 4, 23, 22, 11, 17, 10, 24, 19, 20, 21 },
{ 27, 30, 31, 33, 26, 28, 29, 32, 34, 35, 36 },
};
extern const byte _industry_type_costs[37];
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.landscape][WP(w,def_d).data_1];
SET_DPARAM32(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, 0xFF1, 1, NULL))
WP(w,def_d).data_1 = wid - 3;
}
} break;
case WE_PLACE_OBJ:
if (DoCommandP(e->place.tile, _build_industry_types[_opt.landscape][WP(w,def_d).data_1], 0, NULL, CMD_BUILD_INDUSTRY | CMD_MSG(STR_4830_CAN_T_CONSTRUCT_THIS_INDUSTRY)))
ResetObjectToPlace();
break;
case WE_ABORT_PLACE_OBJ:
w->click_state = 0;
SetWindowDirty(w);
break;
}
}
static const Widget _build_industry_land0_widgets[] = {
{ WWT_CLOSEBOX, 7, 0, 10, 0, 13, STR_00C5,STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, 7, 11, 169, 0, 13, STR_0314_FUND_NEW_INDUSTRY,STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PANEL, 7, 0, 169, 14, 115, 0x0,0},
{ WWT_CLOSEBOX, 14, 2, 167, 16, 27, STR_0241_POWER_STATION,STR_0263_CONSTRUCT_POWER_STATION},
{ WWT_CLOSEBOX, 14, 2, 167, 29, 40, STR_0242_SAWMILL,STR_0264_CONSTRUCT_SAWMILL},
{ WWT_CLOSEBOX, 14, 2, 167, 42, 53, STR_0244_OIL_REFINERY,STR_0266_CONSTRUCT_OIL_REFINERY},
{ WWT_CLOSEBOX, 14, 2, 167, 55, 66, STR_0246_FACTORY,STR_0268_CONSTRUCT_FACTORY},
{ WWT_CLOSEBOX, 14, 2, 167, 68, 79, STR_0247_STEEL_MILL,STR_0269_CONSTRUCT_STEEL_MILL},
{ WWT_LAST},
};
static const Widget _build_industry_land1_widgets[] = {
{ WWT_CLOSEBOX, 7, 0, 10, 0, 13, STR_00C5,STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, 7, 11, 169, 0, 13, STR_0314_FUND_NEW_INDUSTRY,STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PANEL, 7, 0, 169, 14, 115, 0x0,0},
{ WWT_CLOSEBOX, 14, 2, 167, 16, 27, STR_0241_POWER_STATION,STR_0263_CONSTRUCT_POWER_STATION},
{ WWT_CLOSEBOX, 14, 2, 167, 29, 40, STR_024C_PAPER_MILL, STR_026E_CONSTRUCT_PAPER_MILL},
{ WWT_CLOSEBOX, 14, 2, 167, 42, 53, STR_0244_OIL_REFINERY,STR_0266_CONSTRUCT_OIL_REFINERY},
{ WWT_CLOSEBOX, 14, 2, 167, 55, 66, STR_024D_FOOD_PROCESSING_PLANT,STR_026F_CONSTRUCT_FOOD_PROCESSING},
{ WWT_CLOSEBOX, 14, 2, 167, 68, 79, STR_024E_PRINTING_WORKS,STR_0270_CONSTRUCT_PRINTING_WORKS},
{ WWT_LAST},
};
static const Widget _build_industry_land2_widgets[] = {
{ WWT_CLOSEBOX, 7, 0, 10, 0, 13, STR_00C5,STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, 7, 11, 169, 0, 13, STR_0314_FUND_NEW_INDUSTRY,STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PANEL, 7, 0, 169, 14, 115, 0x0,0},
{ WWT_CLOSEBOX, 14, 2, 167, 16, 27, STR_0250_LUMBER_MILL,STR_0273_CONSTRUCT_LUMBER_MILL_TO},
{ WWT_CLOSEBOX, 14, 2, 167, 29, 40, STR_024D_FOOD_PROCESSING_PLANT,STR_026F_CONSTRUCT_FOOD_PROCESSING},
{ WWT_CLOSEBOX, 14, 2, 167, 42, 53, STR_0244_OIL_REFINERY,STR_0266_CONSTRUCT_OIL_REFINERY},
{ WWT_CLOSEBOX, 14, 2, 167, 55, 66, STR_0246_FACTORY,STR_0268_CONSTRUCT_FACTORY},
{ WWT_CLOSEBOX, 14, 2, 167, 68, 79, STR_0254_WATER_TOWER,STR_0277_CONSTRUCT_WATER_TOWER_CAN},
{ WWT_LAST},
};
static const Widget _build_industry_land3_widgets[] = {
{ WWT_CLOSEBOX, 7, 0, 10, 0, 13, STR_00C5,STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, 7, 11, 169, 0, 13, STR_0314_FUND_NEW_INDUSTRY,STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PANEL, 7, 0, 169, 14, 115, 0x0,0},
{ WWT_CLOSEBOX, 14, 2, 167, 16, 27, STR_0258_CANDY_FACTORY,STR_027B_CONSTRUCT_CANDY_FACTORY},
{ WWT_CLOSEBOX, 14, 2, 167, 29, 40, STR_025B_TOY_SHOP,STR_027E_CONSTRUCT_TOY_SHOP},
{ WWT_CLOSEBOX, 14, 2, 167, 42, 53, STR_025C_TOY_FACTORY,STR_027F_CONSTRUCT_TOY_FACTORY},
{ WWT_CLOSEBOX, 14, 2, 167, 55, 66, STR_025E_FIZZY_DRINK_FACTORY,STR_0281_CONSTRUCT_FIZZY_DRINK_FACTORY},
{ WWT_LAST},
};
static const Widget _build_industry_land0_widgets_extra[] = {
{ WWT_CLOSEBOX, 7, 0, 10, 0, 13, STR_00C5,STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, 7, 11, 169, 0, 13, STR_0314_FUND_NEW_INDUSTRY,STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PANEL, 7, 0, 169, 14, 187, 0x0,0},
{ WWT_CLOSEBOX, 14, 2, 167, 16, 27, STR_0241_POWER_STATION,STR_0263_CONSTRUCT_POWER_STATION},
{ WWT_CLOSEBOX, 14, 2, 167, 29, 40, STR_0242_SAWMILL,STR_0264_CONSTRUCT_SAWMILL},
{ WWT_CLOSEBOX, 14, 2, 167, 42, 53, STR_0244_OIL_REFINERY,STR_0266_CONSTRUCT_OIL_REFINERY},
{ WWT_CLOSEBOX, 14, 2, 167, 55, 66, STR_0246_FACTORY,STR_0268_CONSTRUCT_FACTORY},
{ WWT_CLOSEBOX, 14, 2, 167, 68, 79, STR_0247_STEEL_MILL,STR_0269_CONSTRUCT_STEEL_MILL},
{ WWT_CLOSEBOX, 14, 2, 167, 84, 95, STR_0240_COAL_MINE, STR_CONSTRUCT_COAL_MINE_TIP},
{ WWT_CLOSEBOX, 14, 2, 167, 97, 108, STR_0243_FOREST, STR_CONSTRUCT_FOREST_TIP},
{ WWT_CLOSEBOX, 14, 2, 167, 110, 121, STR_0245_OIL_RIG, STR_CONSTRUCT_OIL_RIG_TIP},
{ WWT_CLOSEBOX, 14, 2, 167, 123, 134, STR_0248_FARM, STR_CONSTRUCT_FARM_TIP},
{ WWT_CLOSEBOX, 14, 2, 167, 136, 147, STR_024A_OIL_WELLS, STR_CONSTRUCT_OIL_WELLS_TIP},
{ WWT_CLOSEBOX, 14, 2, 167, 149, 160, STR_0249_IRON_ORE_MINE, STR_CONSTRUCT_IRON_ORE_MINE_TIP},
{ WWT_LAST},
};
static const Widget _build_industry_land1_widgets_extra[] = {
{ WWT_CLOSEBOX, 7, 0, 10, 0, 13, STR_00C5,STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, 7, 11, 169, 0, 13, STR_0314_FUND_NEW_INDUSTRY,STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PANEL, 7, 0, 169, 14, 174, 0x0,0},
{ WWT_CLOSEBOX, 14, 2, 167, 16, 27, STR_0241_POWER_STATION,STR_0263_CONSTRUCT_POWER_STATION},
{ WWT_CLOSEBOX, 14, 2, 167, 29, 40, STR_024C_PAPER_MILL, STR_026E_CONSTRUCT_PAPER_MILL},
{ WWT_CLOSEBOX, 14, 2, 167, 42, 53, STR_0244_OIL_REFINERY,STR_0266_CONSTRUCT_OIL_REFINERY},
{ WWT_CLOSEBOX, 14, 2, 167, 55, 66, STR_024D_FOOD_PROCESSING_PLANT,STR_026F_CONSTRUCT_FOOD_PROCESSING},
{ WWT_CLOSEBOX, 14, 2, 167, 68, 79, STR_024E_PRINTING_WORKS,STR_0270_CONSTRUCT_PRINTING_WORKS},
{ WWT_CLOSEBOX, 14, 2, 167, 81+3, 92+3, STR_0240_COAL_MINE,STR_CONSTRUCT_COAL_MINE_TIP},
{ WWT_CLOSEBOX, 14, 2, 167, 94+3, 105+3, STR_0243_FOREST,STR_CONSTRUCT_FOREST_TIP},
{ WWT_CLOSEBOX, 14, 2, 167, 107+3, 118+3, STR_0248_FARM,STR_CONSTRUCT_FARM_TIP},
{ WWT_CLOSEBOX, 14, 2, 167, 120+3, 131+3, STR_024A_OIL_WELLS,STR_CONSTRUCT_OIL_WELLS_TIP},
{ WWT_CLOSEBOX, 14, 2, 167, 133+3, 144+3, STR_024F_GOLD_MINE,STR_CONSTRUCT_GOLD_MINE_TIP},
{ WWT_LAST},
};
static const Widget _build_industry_land2_widgets_extra[] = {
{ WWT_CLOSEBOX, 7, 0, 10, 0, 13, STR_00C5,STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, 7, 11, 169, 0, 13, STR_0314_FUND_NEW_INDUSTRY,STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PANEL, 7, 0, 169, 14, 200, 0x0,0},
{ WWT_CLOSEBOX, 14, 2, 167, 16, 27, STR_0250_LUMBER_MILL,STR_0273_CONSTRUCT_LUMBER_MILL_TO},
{ WWT_CLOSEBOX, 14, 2, 167, 29, 40, STR_024D_FOOD_PROCESSING_PLANT,STR_026F_CONSTRUCT_FOOD_PROCESSING},
{ WWT_CLOSEBOX, 14, 2, 167, 42, 53, STR_0244_OIL_REFINERY,STR_0266_CONSTRUCT_OIL_REFINERY},
{ WWT_CLOSEBOX, 14, 2, 167, 55, 66, STR_0246_FACTORY,STR_0268_CONSTRUCT_FACTORY},
{ WWT_CLOSEBOX, 14, 2, 167, 68, 79, STR_0254_WATER_TOWER,STR_0277_CONSTRUCT_WATER_TOWER_CAN},
{ WWT_CLOSEBOX, 14, 2, 167, 81+3, 92+3, STR_024A_OIL_WELLS,STR_CONSTRUCT_OIL_WELLS_TIP},
{ WWT_CLOSEBOX, 14, 2, 167, 94+3, 105+3, STR_0255_DIAMOND_MINE,STR_CONSTRUCT_DIAMOND_MINE_TIP},
{ WWT_CLOSEBOX, 14, 2, 167, 107+3, 118+3, STR_0256_COPPER_ORE_MINE,STR_CONSTRUCT_COPPER_ORE_MINE_TIP},
{ WWT_CLOSEBOX, 14, 2, 167, 120+3, 131+3, STR_0248_FARM,STR_CONSTRUCT_FARM_TIP},
{ WWT_CLOSEBOX, 14, 2, 167, 133+3, 144+3, STR_0251_FRUIT_PLANTATION,STR_CONSTRUCT_FRUIT_PLANTATION_TIP},
{ WWT_CLOSEBOX, 14, 2, 167, 146+3, 157+3, STR_0252_RUBBER_PLANTATION,STR_CONSTRUCT_RUBBER_PLANTATION_TIP},
{ WWT_CLOSEBOX, 14, 2, 167, 159+3, 170+3, STR_0253_WATER_SUPPLY,STR_CONSTRUCT_WATER_SUPPLY_TIP},
{ WWT_LAST},
};
static const Widget _build_industry_land3_widgets_extra[] = {
{ WWT_CLOSEBOX, 7, 0, 10, 0, 13, STR_00C5,STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, 7, 11, 169, 0, 13, STR_0314_FUND_NEW_INDUSTRY,STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PANEL, 7, 0, 169, 14, 187, 0x0,0},
{ WWT_CLOSEBOX, 14, 2, 167, 16, 27, STR_0258_CANDY_FACTORY,STR_027B_CONSTRUCT_CANDY_FACTORY},
{ WWT_CLOSEBOX, 14, 2, 167, 29, 40, STR_025B_TOY_SHOP,STR_027E_CONSTRUCT_TOY_SHOP},
{ WWT_CLOSEBOX, 14, 2, 167, 42, 53, STR_025C_TOY_FACTORY,STR_027F_CONSTRUCT_TOY_FACTORY},
{ WWT_CLOSEBOX, 14, 2, 167, 55, 66, STR_025E_FIZZY_DRINK_FACTORY,STR_0281_CONSTRUCT_FIZZY_DRINK_FACTORY},
{ WWT_CLOSEBOX, 14, 2, 167, 68+3, 79+3, STR_0257_COTTON_CANDY_FOREST,STR_CONSTRUCT_COTTON_CANDY_TIP},
{ WWT_CLOSEBOX, 14, 2, 167, 81+3, 92+3, STR_0259_BATTERY_FARM,STR_CONSTRUCT_BATTERY_FARM_TIP},
{ WWT_CLOSEBOX, 14, 2, 167, 94+3, 105+3, STR_025A_COLA_WELLS,STR_CONSTRUCT_COLA_WELLS_TIP},
{ WWT_CLOSEBOX, 14, 2, 167, 107+3, 118+3, STR_025D_PLASTIC_FOUNTAINS,STR_CONSTRUCT_PLASTIC_FOUNTAINS_TIP},
{ WWT_CLOSEBOX, 14, 2, 167, 120+3, 131+3, STR_025F_BUBBLE_GENERATOR,STR_CONSTRUCT_BUBBLE_GENERATOR_TIP},
{ WWT_CLOSEBOX, 14, 2, 167, 133+3, 144+3, STR_0260_TOFFEE_QUARRY,STR_CONSTRUCT_TOFFEE_QUARRY_TIP},
{ WWT_CLOSEBOX, 14, 2, 167, 146+3, 157+3, STR_0261_SUGAR_MINE,STR_CONSTRUCT_SUGAR_MINE_TIP},
{ WWT_LAST},
};
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()
{
AllocateWindowDescFront(_industry_window_desc[_patches.build_rawmaterial_ind][_opt.landscape],0);
}
static void IndustryViewWndProc(Window *w, WindowEvent *e)
{
Industry *i;
StringID str;
switch(e->event) {
case WE_PAINT:
// in editor, use bulldoze to destroy industry
// Destroy Industry button costing money removed per request of dominik
//w->disabled_state = (_patches.extra_dynamite && !_networking && _game_mode != GM_EDITOR) ? 0 : (1 << 6);
i = DEREF_INDUSTRY(w->window_number);
SET_DPARAM16(0, i->town->index);
SET_DPARAM16(1, i->type + STR_4802_COAL_MINE);
DrawWindowWidgets(w);
if (i->accepts_cargo[0] != 0xFF) {
SET_DPARAM16(0, _cargoc.names_s[i->accepts_cargo[0]]);
str = STR_4827_REQUIRES;
if (i->accepts_cargo[1] != 0xFF) {
SET_DPARAM16(1, _cargoc.names_s[i->accepts_cargo[1]]);
str++;
if (i->accepts_cargo[2] != 0xFF) {
SET_DPARAM16(2, _cargoc.names_s[i->accepts_cargo[2]]);
str++;
}
}
DrawString(2, 107, str, 0);
}
if (i->produced_cargo[0] != 0xFF) {
DrawString(2, 117, STR_482A_PRODUCTION_LAST_MONTH, 0);
SET_DPARAM16(1, i->total_production[0]);
SET_DPARAM16(0, _cargoc.names_long_s[i->produced_cargo[0]] + ((i->total_production[0]!=1)<<5));
SET_DPARAM16(2, i->pct_transported[0] * 100 >> 8);
DrawString(4, 127, STR_482B_TRANSPORTED, 0);
if (i->produced_cargo[1] != 0xFF) {
SET_DPARAM16(1, i->total_production[1]);
SET_DPARAM16(0, _cargoc.names_long_s[i->produced_cargo[1]] + ((i->total_production[1]!=1)<<5));
SET_DPARAM16(2, i->pct_transported[1] * 100 >> 8);
DrawString(4, 137, STR_482B_TRANSPORTED, 0);
}
}
DrawWindowViewport(w);
break;
case WE_CLICK:
switch(e->click.widget) {
case 5:
i = DEREF_INDUSTRY(w->window_number);
ScrollMainWindowToTile(i->xy + TILE_XY(1,1));
break;
case 6:
// Destroy Industry button costing money removed per request of dominik
//i = DEREF_INDUSTRY(w->window_number);
/* passing only i->xy is not safe if industry has a weird shape like:
_ X X
X X X
_ <--- grass, no industry, but i->xy points there (first top-left tile)!,
so passing i->xy to destroy industry will fail in called procedure
*/
//DoCommandP(i->xy, w->window_number, 0, CcPlaySound10, CMD_DESTROY_INDUSTRY | CMD_MSG(STR_00B5_CAN_T_CLEAR_THIS_AREA));
break;
}
break;
}
}
static const Widget _industry_view_widgets[] = {
{ WWT_TEXTBTN, 9, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, 9, 11, 259, 0, 13, STR_4801, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_IMGBTN, 9, 0, 259, 14, 105, 0x0},
{ WWT_6, 9, 2, 257, 16, 103, 0x0},
{ WWT_IMGBTN, 9, 0, 259, 106, 147, 0x0},
{ WWT_PUSHTXTBTN, 9, 0, 129, 148, 159, STR_00E4_LOCATION, STR_482C_CENTER_THE_MAIN_VIEW_ON},
{ WWT_IMGBTN, 9, 130, 259, 148, 159, 0x0, 0},
// Destroy Industry button costing money removed per request of dominik
//{ WWT_PUSHTXTBTN, 9, 130, 259, 148, 159, STR_INDUSTRYDIR_DESTROY, STR_482C_DESTROY_INDUSTRY},
{ WWT_LAST},
};
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,
_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;
i = DEREF_INDUSTRY(w->window_number);
AssignWindowViewport(w, 3, 17, 0xFE, 0x56, i->xy + TILE_XY(1,1), 1);
}
}
static const Widget _industry_directory_widgets[] = {
{ WWT_TEXTBTN, 13, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, 13, 11, 507, 0, 13, STR_INDUSTRYDIR_CAPTION, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PUSHTXTBTN, 13, 0, 100, 14, 25, STR_SORT_BY_NAME, STR_SORT_TIP},
{ WWT_PUSHTXTBTN, 13, 101, 200, 14, 25, STR_SORT_BY_TYPE, STR_SORT_TIP},
{ WWT_PUSHTXTBTN, 13, 201, 300, 14, 25, STR_SORT_BY_PRODUCTION, STR_SORT_TIP},
{ WWT_PUSHTXTBTN, 13, 301, 400, 14, 25, STR_SORT_BY_TRANSPORTED, STR_SORT_TIP},
{ WWT_PANEL, 13, 401, 496, 14, 25, 0x0, 0},
{ WWT_IMGBTN, 13, 0, 496, 26, 189, 0x0, STR_200A_TOWN_NAMES_CLICK_ON_NAME},
{ WWT_SCROLLBAR, 13, 497, 507, 14, 189, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
{ WWT_LAST},
};
static byte _industry_sort[lengthof(_industries)];
static uint _num_industry_sort;
static char _bufcache[96];
static byte _last_industry_idx;
static byte _industry_sort_order;
static int CDECL IndustrySorter(const void *a, const void *b)
{
char buf1[96];
Industry *i, *j;
byte val;
int r = 0;
i = DEREF_INDUSTRY(*(byte*)a);
j = DEREF_INDUSTRY(*(byte*)b);
switch (_industry_sort_order >> 1) {
case 0:
r = 0;
break;
case 1: /* Case 1, sort by type */
r = i->type - j->type;
break;
case 2: /* Case 2, sort by production */
if (i->produced_cargo[0] != 0xFF && j->produced_cargo[0] != 0xFF) { //producing any cargo?
if (i->produced_cargo[1] == 0xFF) //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] == 0xFF && j->produced_cargo[0] == 0xFF) //None of them producing anything, let them go to the name-sorting
r = 0;
else if (i->produced_cargo[0] == 0xFF) //Non-producers, end up last/first in list
r = 1;
else
r = -1;
break;
case 3: /* Case 3, sort by transportation */
if (i->produced_cargo[0] != 0xFF && j->produced_cargo[0] != 0xFF) { //producing any cargo?
if (i->produced_cargo[1] == 0xFF) //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] == 0xFF && j->produced_cargo[0] == 0xFF) //None of them producing anything, let them go to the name-sorting
r = 0;
else if (i->produced_cargo[0] == 0xFF) //Non-producers, end up last/first in list
r = 1;
else
r = -1;
break;
}
// default to string sorting if they are otherwise equal
if (r == 0) {
SET_DPARAM32(0, i->town->townnameparts);
GetString(buf1, i->town->townnametype);
if ( (val=*(byte*)b) != _last_industry_idx) {
_last_industry_idx = val;
SET_DPARAM32(0, j->town->townnameparts);
GetString(_bufcache, j->town->townnametype);
}
r = strcmp(buf1, _bufcache);
}
if (_industry_sort_order & 1)
r = -r;
return r;
}
static void MakeSortedIndustryList()
{
Industry *i;
int n = 0, index = 0;
for(i=_industries; i != endof(_industries); i++) {
if(i->xy) _industry_sort[n++] = index;
index++;
}
_num_industry_sort = n;
_last_industry_idx = 255; // used for "cache"
qsort(_industry_sort, n, 1, IndustrySorter);
}
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();
}
w->vscroll.count = _num_industry_sort;
DrawWindowWidgets(w);
DoDrawString(_industry_sort_order & 1 ? "\xAA" : "\xA0", _indicator_positions[_industry_sort_order>>1], 15, 0x10);
p = w->vscroll.pos;
n = 0;
while (p < _num_industry_sort) {
i = DEREF_INDUSTRY(_industry_sort[p]);
SET_DPARAM16(0, i->town->index);
SET_DPARAM16(1, i->type + STR_4802_COAL_MINE);
if (i->produced_cargo[0] != 0xFF) {
SET_DPARAM16(3, i->total_production[0] * 100 >> 8);
SET_DPARAM16(2, _cargoc.names_long_s[i->produced_cargo[0]] + ((i->total_production[0]!=1)<<5));
if (i->produced_cargo[1] != 0xFF) {
SET_DPARAM16(5, i->total_production[1] * 100 >> 8);
SET_DPARAM16(4, _cargoc.names_long_s[i->produced_cargo[1]] + ((i->total_production[1]!=1)<<5));
SET_DPARAM16(6, i->pct_transported[0] * 100 >> 8);
SET_DPARAM16(7, i->pct_transported[1] * 100 >> 8);
DrawString(4, 28+n*10, STR_INDUSTRYDIR_ITEM_TWO, 0);
} else {
SET_DPARAM16(4, 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 == 16)
break;
}
} break;
case WE_CLICK:
switch(e->click.widget) {
case 2: {
_industry_sort_order = _industry_sort_order==0 ? 1 : 0;
_industry_sort_dirty = true;
SetWindowDirty(w);
} break;
case 3: {
_industry_sort_order = _industry_sort_order==2 ? 3 : 2;
_industry_sort_dirty = true;
SetWindowDirty(w);
} break;
case 4: {
_industry_sort_order = _industry_sort_order==4 ? 5 : 4;
_industry_sort_dirty = true;
SetWindowDirty(w);
} break;
case 5: {
_industry_sort_order = _industry_sort_order==6 ? 7 : 6;
_industry_sort_dirty = true;
SetWindowDirty(w);
} break;
case 7: {
int y = (e->click.pt.y - 28) / 10;
byte p;
Industry *c;
if (!IS_INT_INSIDE(y, 0, 16))
return;
p = y + w->vscroll.pos;
if (p < _num_industry_sort) {
c = DEREF_INDUSTRY(_industry_sort[p]);
ScrollMainWindowToTile(c->xy);
}
} break;
}
break;
case WE_4:
SetWindowDirty(w);
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,
_industry_directory_widgets,
IndustryDirectoryWndProc
};
void ShowIndustryDirectory()
{
/* Industry List */
Window *w;
w = AllocateWindowDescFront(&_industry_directory_desc, 0);
if (w) {
w->vscroll.cap = 16;
SetWindowDirty(w);
}
}

@ -0,0 +1,277 @@
#include "stdafx.h"
#include "ttd.h"
#include "window.h"
#include "gui.h"
#include "viewport.h"
#include "gfx.h"
#include "player.h"
#include "command.h"
extern void MakeNewGame();
extern void StartScenario();
/*
static void ShowSelectTutorialWindow()
{
}
*/
static const Widget _select_game_widgets[] = {
{ WWT_CAPTION, 13, 0, 335, 0, 13, STR_0307_TRANSPORT_TYCOON_DELUXE},
{ WWT_IMGBTN, 13, 0, 335, 14, 196, 0x0},
{ WWT_PUSHTXTBTN, 12, 10, 167, 22, 33, STR_0140_NEW_GAME, STR_02FB_START_A_NEW_GAME},
{ WWT_PUSHTXTBTN, 12, 168, 325, 22, 33, STR_0141_LOAD_GAME, STR_02FC_LOAD_A_SAVED_GAME_FROM},
//{ WWT_PUSHTXTBTN, 12, 10, 167, 177, 188, STR_0142_TUTORIAL_DEMONSTRATION, STR_02FD_VIEW_DEMONSTRATIONS_TUTORIALS},
{ WWT_PUSHTXTBTN, 12, 10, 167, 177, 188, STR_CONFIG_PATCHES, STR_CONFIG_PATCHES_TIP},
{ WWT_PUSHTXTBTN, 12, 10, 167, 40, 51, STR_0220_CREATE_SCENARIO, STR_02FE_CREATE_A_CUSTOMIZED_GAME},
{ WWT_PUSHTXTBTN, 12, 10, 167, 136, 147, STR_SINGLE_PLAYER, STR_02FF_SELECT_SINGLE_PLAYER_GAME},
{ WWT_PUSHTXTBTN, 12, 168, 325, 136, 147, STR_MULTIPLAYER, STR_0300_SELECT_TWO_PLAYER_GAME},
{ WWT_PUSHTXTBTN, 12, 10, 167, 159, 170, STR_0148_GAME_OPTIONS, STR_0301_DISPLAY_GAME_OPTIONS},
{ WWT_PUSHTXTBTN, 12, 168, 325, 159, 170, STR_01FE_DIFFICULTY,STR_0302_DISPLAY_DIFFICULTY_OPTIONS},
{ WWT_PUSHTXTBTN, 12, 168, 325, 40, 51, STR_029A_PLAY_SCENARIO, STR_0303_START_A_NEW_GAME_USING},
{ WWT_PUSHTXTBTN, 12, 168, 325, 177, 188, STR_0304_QUIT, STR_0305_LEAVE_TRANSPORT_TYCOON},
{ WWT_PANEL_2, 12, 10, 85, 69, 122, 0x1312, STR_030E_SELECT_TEMPERATE_LANDSCAPE},
{ WWT_PANEL_2, 12, 90, 165, 69, 122, 0x1314, STR_030F_SELECT_SUB_ARCTIC_LANDSCAPE},
{ WWT_PANEL_2, 12, 170, 245, 69, 122, 0x1316, STR_0310_SELECT_SUB_TROPICAL_LANDSCAPE},
{ WWT_PANEL_2, 12, 250, 325, 69, 122, 0x1318, STR_0311_SELECT_TOYLAND_LANDSCAPE},
{ WWT_LAST},
};
static void SelectGameWndProc(Window *w, WindowEvent *e) {
switch(e->event) {
case WE_PAINT:
w->click_state = (w->click_state & ~(0xC0) & ~(0xF << 12)) | (1 << (_new_opt.landscape+12)) | (!_networking?(1<<6):(1<<7));
w->disabled_state = _networking ? 0x30 : 0;
SET_DPARAM16(0, STR_6801_EASY + _new_opt.diff_level);
DrawWindowWidgets(w);
break;
case WE_CLICK:
switch(e->click.widget) {
case 2: DoCommandP(0, 0, 0, NULL, CMD_START_NEW_GAME); break;
case 3: ShowSaveLoadDialog(SLD_LOAD_GAME); break;
case 4: ShowPatchesSelection(); break;
case 5: DoCommandP(0, InteractiveRandom(), 0, NULL, CMD_CREATE_SCENARIO); break;
case 6:
if (_networking)
DoCommandP(0, 0, 0, NULL, CMD_SET_SINGLE_PLAYER);
break;
case 7:
ShowNetworkGameWindow();
break;
case 8: ShowGameOptions(); break;
case 9: ShowGameDifficulty(); break;
case 10:ShowSaveLoadDialog(SLD_LOAD_SCENARIO); break;
case 11:AskExitGame(); break;
case 12: case 13: case 14: case 15:
DoCommandP(0, e->click.widget - 12, 0, NULL, CMD_SET_NEW_LANDSCAPE_TYPE);
break;
}
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()
{
AllocateWindowDesc(&_select_game_desc);
}
// p1 = mode
// 0 - start new game
// 1 - close new game dialog
int32 CmdStartNewGame(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
if (!(flags & DC_EXEC))
return 0;
switch(p1) {
case 0: // show select game window
AskForNewGameToStart();
break;
case 1: // close select game window
DeleteWindowById(WC_SAVELOAD, 0);
break;
}
return 0;
}
int32 CmdGenRandomNewGame(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
if (!(flags & DC_EXEC))
return 0;
// this forces stuff into test mode.
_docommand_recursive = 0;
_random_seed_1 = p1;
_random_seed_2 = p2;
if (_networking) { NetworkStartSync(); }
MakeNewGame();
return 0;
}
int32 CmdLoadGame(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
if (!(flags & DC_EXEC))
return 0;
// ShowSaveLoadDialog(0);
return 0;
}
int32 CmdCreateScenario(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
if (!(flags & DC_EXEC))
return 0;
_switch_mode = SM_EDITOR;
return 0;
}
int32 CmdSetSinglePlayer(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
printf("CmdSetSinglePlayer\n");
return 0;
}
int32 CmdStartScenario(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
if (!(flags & DC_EXEC))
return 0;
// this forces stuff into test mode.
_docommand_recursive = 0;
_random_seed_1 = p1;
_random_seed_2 = p2;
if (_networking) { NetworkStartSync(); }
StartScenario();
return 0;
}
static const Widget _ask_abandon_game_widgets[] = {
{ WWT_TEXTBTN, 4, 0, 10, 0, 13, STR_00C5},
{ WWT_CAPTION, 4, 11, 179, 0, 13, STR_00C7_QUIT},
{ WWT_IMGBTN, 4, 0, 179, 14, 91, 0x0},
{ WWT_TEXTBTN, 12, 25, 84, 72, 83, STR_00C9_NO},
{ WWT_TEXTBTN, 12, 95, 154, 72, 83, STR_00C8_YES},
{ WWT_LAST},
};
static void AskAbandonGameWndProc(Window *w, WindowEvent *e) {
switch(e->event) {
case WE_PAINT:
DrawWindowWidgets(w);
#if defined(_WIN32)
SET_DPARAM16(0, STR_0133_WINDOWS);
#elif defined(__APPLE__)
SET_DPARAM16(0, STR_0135_OSX);
#elif defined(__BEOS__)
SET_DPARAM16(0, STR_OSNAME_BEOS);
#elif defined(__MORPHOS__)
SET_DPARAM16(0, STR_OSNAME_MORPHOS);
#else
SET_DPARAM16(0, STR_0134_UNIX);
#endif
DrawStringMultiCenter(0x5A, 0x26, 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;
}
}
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()
{
AllocateWindowDescFront(&_ask_abandon_game_desc, 0);
}
static const Widget _ask_quit_game_widgets[] = {
{ WWT_TEXTBTN, 4, 0, 10, 0, 13, STR_00C5},
{ WWT_CAPTION, 4, 11, 179, 0, 13, STR_0161_QUIT_GAME},
{ WWT_IMGBTN, 4, 0, 179, 14, 91, 0x0},
{ WWT_TEXTBTN, 12, 25, 84, 72, 83, STR_00C9_NO},
{ WWT_TEXTBTN, 12, 95, 154, 72, 83, STR_00C8_YES},
{ WWT_LAST},
};
static void AskQuitGameWndProc(Window *w, WindowEvent *e) {
switch(e->event) {
case WE_PAINT:
DrawWindowWidgets(w);
DrawStringMultiCenter(0x5A, 0x26,
_game_mode != GM_EDITOR ? STR_0160_ARE_YOU_SURE_YOU_WANT_TO :
STR_029B_ARE_YOU_SURE_YOU_WANT_TO,
178);
return;
case WE_CLICK:
switch(e->click.widget) {
case 3:
DeleteWindow(w);
break;
case 4:
_switch_mode = SM_MENU;
break;
}
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()
{
AllocateWindowDescFront(&_ask_quit_game_desc, 0);
}
int32 CmdSetNewLandscapeType(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
if (flags & DC_EXEC) {
// XXX: some stuff
_new_opt.landscape = p1;
InvalidateWindowClasses(WC_SELECT_GAME);
}
return 0;
}

@ -0,0 +1,727 @@
#include "stdafx.h"
#include "ttd.h"
#include <stdarg.h>
#include "gfx.h"
#include "viewport.h"
#include "command.h"
#include "vehicle.h"
byte _map_type_and_height[TILES_X * TILES_Y];
byte _map5[TILES_X * TILES_Y];
byte _map3_lo[TILES_X * TILES_Y];
byte _map3_hi[TILES_X * TILES_Y];
byte _map_owner[TILES_X * TILES_Y];
byte _map2[TILES_X * TILES_Y];
byte _map_extra_bits[TILES_X * TILES_Y/4];
extern const TileTypeProcs
_tile_type_clear_procs,
_tile_type_rail_procs,
_tile_type_road_procs,
_tile_type_town_procs,
_tile_type_trees_procs,
_tile_type_station_procs,
_tile_type_water_procs,
_tile_type_dummy_procs,
_tile_type_industry_procs,
_tile_type_tunnelbridge_procs,
_tile_type_unmovable_procs;
const TileTypeProcs * const _tile_type_procs[16] = {
&_tile_type_clear_procs,
&_tile_type_rail_procs,
&_tile_type_road_procs,
&_tile_type_town_procs,
&_tile_type_trees_procs,
&_tile_type_station_procs,
&_tile_type_water_procs,
&_tile_type_dummy_procs,
&_tile_type_industry_procs,
&_tile_type_tunnelbridge_procs,
&_tile_type_unmovable_procs,
};
/* landscape slope => sprite */
const byte _tileh_to_sprite[32] = {
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,0,
0,0,0,0,0,0,0,16,0,0,0,17,0,15,18,0,
};
uint GetTileSlope(uint tile, int *h)
{
uint a,b,c,d,min;
int r;
if (GET_TILE_X(tile) == TILE_X_MAX || GET_TILE_Y(tile) == TILE_Y_MAX) {
if (h)
*h = 0;
return 0;
}
assert(tile < TILES_X * TILES_Y && GET_TILE_X(tile) != TILE_X_MAX && GET_TILE_Y(tile) != TILE_Y_MAX);
min = a = _map_type_and_height[tile] & 0xF;
b = _map_type_and_height[tile+TILE_XY(1,0)] & 0xF;
if (min >= b) min = b;
c = _map_type_and_height[tile+TILE_XY(0,1)] & 0xF;
if (min >= c) min = c;
d = _map_type_and_height[tile+TILE_XY(1,1)] & 0xF;
if (min >= d) min = d;
r = 0;
if ((a-=min)!=0) { r += (--a << 4) + 8; }
if ((c-=min)!=0) { r += (--c << 4) + 4; }
if ((d-=min)!=0) { r += (--d << 4) + 2; }
if ((b-=min)!=0) { r += (--b << 4) + 1; }
if (h != 0)
*h = min * 8;
return r;
}
int GetTileZ(uint tile)
{
int h;
GetTileSlope(tile, &h);
return h;
}
void FindLandscapeHeightByTile(TileInfo *ti, uint tile)
{
if (GET_TILE_X(tile) == TILE_X_MAX ||
GET_TILE_Y(tile) == TILE_Y_MAX) {
ti->tileh = 0;
ti->type = MP_STRANGE;
ti->tile = 0;
ti->map5 = 0;
ti->z = 0;
return;
}
ti->tile = tile;
ti->map5 = _map5[tile];
ti->type = GET_TILETYPE(tile);
ti->tileh = GetTileSlope(tile, &ti->z);
// ti->z = min * 8;
}
/* find the landscape height for the coordinates x y */
void FindLandscapeHeight(TileInfo *ti, uint x, uint y)
{
int tile;
ti->x = x;
ti->y = y;
if (x >= TILE_X_MAX*16-1 || y >= TILE_Y_MAX*16-1) {
ti->tileh = 0;
ti->type = MP_STRANGE;
ti->tile = 0;
ti->map5 = 0;
ti->z = 0;
return;
}
tile = TILE_FROM_XY(x,y);
FindLandscapeHeightByTile(ti, tile);
}
uint GetPartialZ(int x, int y, int corners)
{
int z = 0;
switch(corners) {
case 1:
if (x - y >= 0)
z = (x - y) >> 1;
break;
case 2:
y^=0xF;
if ( (x - y) >= 0)
z = (x - y) >> 1;
break;
case 3:
z = (x>>1) + 1;
break;
case 4:
if (y - x >= 0)
z = (y - x) >> 1;
break;
case 5:
case 10:
case 15:
z = 4;
break;
case 6:
z = (y>>1) + 1;
break;
case 7:
z = 8;
y^=0xF;
if (x - y < 0)
z += (x - y) >> 1;
break;
case 8:
y ^= 0xF;
if (y - x >= 0)
z = (y - x) >> 1;
break;
case 9:
z = (y^0xF)>>1;
break;
case 11:
z = 8;
if (x - y < 0)
z += (x - y) >> 1;
break;
case 12:
z = (x^0xF)>>1;
break;
case 13:
z = 8;
y ^= 0xF;
if (y - x < 0)
z += (y - x) >> 1;
break;
case 14:
z = 8;
if (y - x < 0)
z += (y - x) >> 1;
break;
case 23:
z = 1 + ((x+y)>>1);
break;
case 27:
z = 1 + ((x+(y^0xF))>>1);
break;
case 29:
z = 1 + (((x^0xF)+(y^0xF))>>1);
break;
case 30:
z = 1 + (((x^0xF)+(y^0xF))>>1);
break;
}
return z;
}
uint GetSlopeZ(int x, int y)
{
TileInfo ti;
// int z;
FindLandscapeHeight(&ti, x, y);
/*
z = ti.z;
x &= 0xF;
y &= 0xF;
assert(z < 256);
*/
return _tile_type_procs[ti.type]->get_slope_z_proc(&ti);
}
void DrawFoundation(TileInfo *ti, uint f)
{
if (f < 15) {
// leveled foundation
AddSortableSpriteToDraw(f + 0x3DE - 1, ti->x, ti->y, 16, 16, 7, ti->z);
ti->z += 8;
ti->tileh = 0;
OffsetGroundSprite(31, 1);
} else {
// inclined foundation
AddSortableSpriteToDraw(
HASBIT( (1<<1) | (1<<2) | (1<<4) | (1<<8), ti->tileh) ? (SPR_OPENTTD_BASE+17) + (f - 15) : ti->tileh + 0x3DE - 1,
ti->x, ti->y, 1, 1, 1, ti->z
);
ti->tileh = _inclined_tileh[f - 15];
OffsetGroundSprite(31, 9);
}
}
void DoClearSquare(uint tile)
{
ModifyTile(tile,
MP_SETTYPE(MP_CLEAR) |
MP_MAP2_CLEAR | MP_MAP3LO_CLEAR | MP_MAP3HI_CLEAR | MP_MAPOWNER | MP_MAP5,
OWNER_NONE, /* map_owner */
_generating_world ? 3 : 0 /* map5 */
);
}
uint32 GetTileTrackStatus(uint tile, int mode)
{
return _tile_type_procs[GET_TILETYPE(tile)]->get_tile_track_status_proc(tile, mode);
}
void ChangeTileOwner(uint tile, byte old_player, byte new_player)
{
_tile_type_procs[GET_TILETYPE(tile)]->change_tile_owner_proc(tile, old_player, new_player);
}
void GetAcceptedCargo(uint tile, AcceptedCargo *ac)
{
memset(ac, 0, sizeof(AcceptedCargo));
_tile_type_procs[GET_TILETYPE(tile)]->get_accepted_cargo_proc(tile, ac);
}
void AnimateTile(uint tile)
{
_tile_type_procs[GET_TILETYPE(tile)]->animate_tile_proc(tile);
}
void ClickTile(uint tile)
{
_tile_type_procs[GET_TILETYPE(tile)]->click_tile_proc(tile);
}
void DrawTile(TileInfo *ti)
{
_tile_type_procs[ti->type]->draw_tile_proc(ti);
}
void GetTileDesc(uint tile, TileDesc *td)
{
_tile_type_procs[GET_TILETYPE(tile)]->get_tile_desc_proc(tile, td);
}
/* Clear a piece of landscape
* p1 = 0,
* p2 = 0
*/
int32 CmdLandscapeClear(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
uint tile;
SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
tile = TILE_FROM_XY(x,y);
return _tile_type_procs[GET_TILETYPE(tile)]->clear_tile_proc(tile, flags);
}
// p1 = end tile
int32 CmdClearArea(int ex, int ey, uint32 flags, uint32 p1, uint32 p2)
{
int32 cost,ret, money;
int sx,sy;
int x,y;
bool success = false;
// make sure sx,sy are smaller than ex,ey
sx = GET_TILE_X(p1)*16;
sy = GET_TILE_Y(p1)*16;
if (ex < sx) intswap(ex, sx);
if (ey < sy) intswap(ey, sy);
money = GetAvailableMoneyForCommand();
cost = 0;
for(x=sx; x<=ex; x+=16) {
for(y=sy; y<=ey; y+=16) {
ret = DoCommandByTile(TILE_FROM_XY(x,y), 0, 0, flags &~DC_EXEC, CMD_LANDSCAPE_CLEAR);
if (ret == CMD_ERROR) continue;
cost += ret;
success = true;
if (flags & DC_EXEC) {
if ( ret>0 && (money -= ret) < 0) {
_additional_cash_required = ret;
return cost - ret;
}
DoCommandByTile(TILE_FROM_XY(x,y), 0, 0, flags, CMD_LANDSCAPE_CLEAR);
// draw explosion animation...
if ((x==sx || x==ex) && (y==sy || y==ey)) {
// big explosion in each corner, or small explosion for single tiles
CreateEffectVehicleAbove(x + 8,y + 8, 2, sy==ey && sx==ex ? EV_DEMOLISH : EV_CRASHED_SMOKE);
}
}
}
}
if (!success)
cost = CMD_ERROR;
return cost;
}
/* utility function used to modify a tile */
void CDECL ModifyTile(uint tile, uint flags, ...)
{
va_list va;
int i;
va_start(va, flags);
if ((i = (flags >> 8) & 0xF) != 0) {
_map_type_and_height[tile] = (_map_type_and_height[tile]&~0xF0)|((i-1) << 4);
}
if (flags & (MP_MAP2_CLEAR | MP_MAP2)) {
int x = 0;
if (flags & MP_MAP2) x = va_arg(va, int);
_map2[tile] = x;
}
if (flags & (MP_MAP3LO_CLEAR | MP_MAP3LO)) {
int x = 0;
if (flags & MP_MAP3LO) x = va_arg(va, int);
_map3_lo[tile] = x;
}
if (flags & (MP_MAP3HI_CLEAR | MP_MAP3HI)) {
int x = 0;
if (flags & MP_MAP3HI) x = va_arg(va, int);
_map3_hi[tile] = x;
}
if (flags & (MP_MAPOWNER|MP_MAPOWNER_CURRENT)) {
byte x = _current_player;
if (flags & MP_MAPOWNER) x = va_arg(va, int);
_map_owner[tile] = x;
}
if (flags & MP_MAP5) {
_map5[tile] = va_arg(va, int);
}
va_end(va);
if (!(flags & MP_NODIRTY))
MarkTileDirtyByTile(tile);
}
void SetMapExtraBits(uint tile, byte bits)
{
_map_extra_bits[tile >> 2] &= ~(3 << ((tile&3)*2));
_map_extra_bits[tile >> 2] |= (bits&3) << ((tile&3)*2);
}
uint GetMapExtraBits(uint tile)
{
return (_map_extra_bits[tile >> 2] >> (tile&3)*2)&3;
}
#define TILELOOP_BITS 4
#define TILELOOP_SIZE (1 << TILELOOP_BITS)
#define TILELOOP_ASSERTMASK ((TILELOOP_SIZE-1) + ((TILELOOP_SIZE-1) << TILE_X_BITS))
#define TILELOOP_CHKMASK (((1 << (TILE_X_BITS - TILELOOP_BITS))-1) << TILELOOP_BITS)
void RunTileLoop()
{
uint tile;
uint count;
tile = _cur_tileloop_tile;
assert( (tile & ~TILELOOP_ASSERTMASK) == 0);
count = (TILES_X/TILELOOP_SIZE) * (TILES_Y/TILELOOP_SIZE);
do {
_tile_type_procs[GET_TILETYPE(tile)]->tile_loop_proc(tile);
if ( GET_TILE_X(tile) < TILES_X - TILELOOP_SIZE) {
tile += TILELOOP_SIZE; /* no overflow */
} else {
tile = TILE_MASK(tile - TILELOOP_SIZE * (TILES_X/TILELOOP_SIZE-1) + TILE_XY(0, TILELOOP_SIZE)); /* x would overflow, also increase y */
}
} while (--count);
assert( (tile & ~TILELOOP_ASSERTMASK) == 0);
tile += 9;
if (tile & TILELOOP_CHKMASK)
tile = (tile + TILES_X) & TILELOOP_ASSERTMASK;
_cur_tileloop_tile = tile;
}
void InitializeLandscape()
{
int i;
memset(_map_owner, OWNER_NONE, sizeof(_map_owner));
memset(_map2, 0, sizeof(_map2));
memset(_map3_lo, 0, sizeof(_map3_lo));
memset(_map3_hi, 0, sizeof(_map3_hi));
memset(_map_extra_bits, 0, sizeof(_map_extra_bits));
memset(_map_type_and_height, MP_WATER << 4, sizeof(_map_type_and_height));
for(i=0; i!=TILES_Y-1; i++)
memset(_map_type_and_height + i*TILES_X, 0, TILES_X-1);
memset(_map5, 3, sizeof(_map5));
}
void ConvertGroundTilesIntoWaterTiles()
{
uint tile = 0;
int h;
while(true) {
if (IS_TILETYPE(tile, MP_CLEAR) && GetTileSlope(tile, &h) == 0 && h == 0) {
_map_type_and_height[tile] = MP_WATER << 4;
_map5[tile] = 0;
_map_owner[tile] = OWNER_WATER;
}
tile++;
if (GET_TILE_X(tile) == TILE_X_MAX) {
tile += TILE_XY(-TILE_X_MAX, 1);
if (GET_TILE_Y(tile) == TILE_Y_MAX)
break;
}
}
}
static const byte _genterrain_tbl_1[5] = { 10, 22, 33, 37, 4 };
static const byte _genterrain_tbl_2[5] = { 0, 0, 0, 0, 33 };
static void GenerateTerrain(int type, int flag)
{
uint32 r;
int x,y;
int w,h;
byte *p,*tile;
byte direction;
r = Random();
p = GetSpritePtr((((r >> 24) * _genterrain_tbl_1[type]) >> 8) + _genterrain_tbl_2[type] + 4845);
x = r & TILE_X_MAX;
y = (r >> TILE_X_BITS) & TILE_Y_MAX;
if (x < 2 || y < 2)
return;
direction = (byte)(r >> 22) & 3;
w = p[2];
h = p[1];
if (direction & 1) { w = p[1]; h = p[2]; }
p += 8;
if (flag & 4) {
if (!(flag & 2)) {
if (!(flag & 1)) {
if (x + y > 190)
return;
} else {
if (y < 30 + x)
return;
}
} else {
if (!(flag & 1)) {
if (x + y < 256)
return;
} else {
if (x < 30 + y)
return;
}
}
}
if (x + w >= TILE_X_MAX-1)
return;
if (y + h >= TILE_Y_MAX-1)
return;
tile = &_map_type_and_height[TILE_XY(x,y)];
if (direction == 0) {
do {
int w_cur = w;
byte *tile_cur = tile;
do {
if (*p >= *tile_cur) *tile_cur = *p;
p++;
tile_cur++;
} while (--w_cur != 0);
tile += TILE_XY(0,1);
} while (--h != 0);
} else if (direction == 1) {
do {
int h_cur = h;
byte *tile_cur = tile;
do {
if (*p >= *tile_cur) *tile_cur = *p;
p++;
tile_cur+=TILE_XY(0,1);
} while (--h_cur != 0);
tile++;
} while (--w != 0);
} else if (direction == 2) {
tile += w - 1;
do {
int w_cur = w;
byte *tile_cur = tile;
do {
if (*p >= *tile_cur) *tile_cur = *p;
p++;
tile_cur--;
} while (--w_cur != 0);
tile += TILE_XY(0,1);
} while (--h != 0);
} else {
tile += (h - 1) * TILE_XY(0,1);
do {
int h_cur = h;
byte *tile_cur = tile;
do {
if (*p >= *tile_cur) *tile_cur = *p;
p++;
tile_cur-=TILE_XY(0,1);
} while (--h_cur != 0);
tile++;
} while (--w != 0);
}
}
#include "table/genland.h"
static void CreateDesertOrRainForest()
{
uint tile;
const TileIndexDiff *data;
byte mt;
int i;
tile = 0;
do {
data = _make_desert_or_rainforest_data;
do {
if ((i = *data++) == MDORD_LAST) {
SetMapExtraBits(tile, 1);
break;
}
mt = _map_type_and_height[tile + i];
} while ((mt & 0xC) == 0 && (mt >> 4) != MP_WATER);
} while (++tile != TILES_X*TILES_Y);
for(i=0; i!=256; i++)
RunTileLoop();
tile = 0;
do {
data = _make_desert_or_rainforest_data;
do {
if ((i = *data++) == MDORD_LAST) {
SetMapExtraBits(tile, 2);
break;
}
} while ( !IS_TILETYPE(tile+i, MP_CLEAR) || (_map5[tile + i]&0x1C) != 0x14);
} while (++tile != TILES_X*TILES_Y);
}
void GenerateLandscape()
{
int i,flag;
uint32 r;
if (_opt.landscape == LT_HILLY) {
i = ((Random() & 0x7F) + 950) * LANDSCAPE_SIZE_FACTOR;
do {
GenerateTerrain(2, 0);
} while (--i);
r = Random();
flag = (r & 3) | 4;
i = (((r >> 16) & 0x7F) + 450) * LANDSCAPE_SIZE_FACTOR;
do {
GenerateTerrain(4, flag);
} while (--i);
} else if (_opt.landscape == LT_DESERT) {
i = ((Random()&0x7F) + 170) * LANDSCAPE_SIZE_FACTOR;
do {
GenerateTerrain(0, 0);
} while (--i);
r = Random();
flag = (r & 3) | 4;
i = (((r >> 16) & 0xFF) + 1700) * LANDSCAPE_SIZE_FACTOR;
do {
GenerateTerrain(0, flag);
} while (--i);
flag ^= 2;
i = ((Random() & 0x7F) + 410) * LANDSCAPE_SIZE_FACTOR;
do {
GenerateTerrain(3, flag);
} while (--i);
} else {
i = ((Random() & 0x7F) + (3 - _opt.diff.quantity_sea_lakes)*256 + 100) * LANDSCAPE_SIZE_FACTOR;
do {
GenerateTerrain(_opt.diff.terrain_type, 0);
} while (--i);
}
ConvertGroundTilesIntoWaterTiles();
if (_opt.landscape == LT_DESERT)
CreateDesertOrRainForest();
}
void OnTick_Town();
void OnTick_Trees();
void OnTick_Station();
void OnTick_Industry();
void OnTick_Players();
void OnTick_Train();
void CallLandscapeTick()
{
OnTick_Town();
OnTick_Trees();
OnTick_Station();
OnTick_Industry();
OnTick_Players();
OnTick_Train();
}
TileIndex AdjustTileCoordRandomly(TileIndex a, byte rng)
{
int rn = rng;
uint32 r = Random();
return TILE_XY(
GET_TILE_X(a) + ((byte)r * rn * 2 >> 8) - rn,
GET_TILE_Y(a) + ((byte)(r>>8) * rn * 2 >> 8) - rn
);
}
uint TileAddWrap(TileIndex tile, int add)
{
uint t = tile + add;
if (t < TILES_X * TILE_Y_MAX && GET_TILE_X(t) != TILE_X_MAX)
return t;
return TILE_WRAPPED;
}
bool IsValidTile(uint tile)
{
return (tile < TILES_X * TILE_Y_MAX && GET_TILE_X(tile) != TILE_X_MAX);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,141 @@
# Microsoft Developer Studio Project File - Name="langs" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Generic Project" 0x010a
CFG=langs - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "langs.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "langs.mak" CFG="langs - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "langs - Win32 Debug" (based on "Win32 (x86) Generic Project")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
MTL=midl.exe
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "langs___Win32_Debug"
# PROP BASE Intermediate_Dir "langs___Win32_Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir ""
# PROP Intermediate_Dir ""
# PROP Target_Dir ""
# Begin Target
# Name "langs - Win32 Debug"
# Begin Source File
SOURCE=.\lang\czech.txt
# Begin Custom Build
InputPath=.\lang\czech.txt
"lang\czech.lng" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
strgen\debug\strgen.exe lang\czech.txt
# End Custom Build
# End Source File
# Begin Source File
SOURCE=.\lang\english.txt
# Begin Custom Build
InputPath=.\lang\english.txt
"lang\english.lng" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
strgen\debug\strgen.exe
# End Custom Build
# End Source File
# Begin Source File
SOURCE=.\lang\french.txt
# Begin Custom Build
InputPath=.\lang\french.txt
"lang\french.lng" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
strgen\debug\strgen.exe lang\french.txt
# End Custom Build
# End Source File
# Begin Source File
SOURCE=.\lang\german.txt
# Begin Custom Build
InputPath=.\lang\german.txt
"lang\german.lng" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
strgen\debug\strgen.exe lang\german.txt
# End Custom Build
# End Source File
# Begin Source File
SOURCE=.\lang\hungarian.txt
# Begin Custom Build
InputPath=.\lang\hungarian.txt
"lang\hungarian.lng" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
strgen\debug\strgen.exe lang\hungarian.txt
# End Custom Build
# End Source File
# Begin Source File
SOURCE=.\lang\italian.txt
# Begin Custom Build
InputPath=.\lang\italian.txt
"lang\italian.lng" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
strgen\debug\strgen.exe lang\italian.txt
# End Custom Build
# End Source File
# Begin Source File
SOURCE=.\lang\norwegian.txt
# Begin Custom Build
InputPath=.\lang\norwegian.txt
"lang\norwegian.lng" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
strgen\debug\strgen.exe lang\norwegian.txt
# End Custom Build
# End Source File
# Begin Source File
SOURCE=.\lang\slovak.txt
# Begin Custom Build
InputPath=.\lang\slovak.txt
"lang\slovak.lng" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
strgen\debug\strgen.exe lang\slovak.txt
# End Custom Build
# End Source File
# Begin Source File
SOURCE=.\lang\swedish.txt
# Begin Custom Build
InputPath=.\lang\swedish.txt
"lang\swedish.lng" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
strgen\debug\strgen.exe lang\swedish.txt
# End Custom Build
# End Source File
# End Target
# End Project

@ -0,0 +1,186 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="langs"
ProjectGUID="{0F066B23-18DF-4284-8265-F4A5E7E3B966}"
RootNamespace="langs"
SccProjectName=""
SccLocalPath=""
Keyword="MakeFileProj">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="."
IntermediateDirectory="."
ConfigurationType="10"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="FALSE">
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCMIDLTool"
TypeLibraryName="./langs.tlb"
HeaderFileName=""/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"
Description="Generating strings.h"
CommandLine="strgen\debug\strgen.exe"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<File
RelativePath=".\lang\czech.txt">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCustomBuildTool"
Description="Generating czech language file"
CommandLine="strgen\debug\strgen.exe &quot;$(InputPath)&quot;"
Outputs="lang\czech.lng"/>
</FileConfiguration>
</File>
<File
RelativePath=".\lang\danish.txt">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCustomBuildTool"
Description="Generating danish language file"
CommandLine="strgen\debug\strgen.exe &quot;$(InputPath)&quot;"
Outputs="lang\danish.lng"/>
</FileConfiguration>
</File>
<File
RelativePath=".\lang\dutch.txt">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCustomBuildTool"
Description="Generating dutch language file"
CommandLine="strgen\debug\strgen.exe &quot;$(InputPath)&quot;"
Outputs="lang\dutch.lng"/>
</FileConfiguration>
</File>
<File
RelativePath="lang\english.txt">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCustomBuildTool"
Description="Generating english language file"
CommandLine="strgen\debug\strgen.exe &quot;$(InputPath)&quot;"
Outputs="lang\english.lng"/>
</FileConfiguration>
</File>
<File
RelativePath=".\lang\french.txt">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCustomBuildTool"
Description="Generating french language file"
CommandLine="strgen\debug\strgen.exe &quot;$(InputPath)&quot;"
Outputs="lang\french.lng"/>
</FileConfiguration>
</File>
<File
RelativePath=".\lang\galician.txt">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCustomBuildTool"
Description="Generating galician language file"
CommandLine="strgen\debug\strgen.exe &quot;$(InputPath)&quot;"
Outputs="lang\galician.lng"/>
</FileConfiguration>
</File>
<File
RelativePath=".\lang\german.txt">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCustomBuildTool"
Description="Generating german language file"
CommandLine="strgen\debug\strgen.exe &quot;$(InputPath)&quot;"
Outputs="lang\german.lng"/>
</FileConfiguration>
</File>
<File
RelativePath=".\lang\hungarian.txt">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCustomBuildTool"
Description="Generating hungarian language file"
CommandLine="strgen\debug\strgen.exe &quot;$(InputPath)&quot;"
Outputs="lang\hungarian.lng"/>
</FileConfiguration>
</File>
<File
RelativePath=".\lang\italian.txt">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCustomBuildTool"
Description="Generating italian language file"
CommandLine="strgen\debug\strgen.exe &quot;$(InputPath)&quot;"
Outputs="lang\italian.lng"/>
</FileConfiguration>
</File>
<File
RelativePath=".\lang\norwegian.txt">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCustomBuildTool"
Description="Generating norwegian language file"
CommandLine="strgen\debug\strgen.exe &quot;$(InputPath)&quot;"
Outputs="lang\norwegian.lng"/>
</FileConfiguration>
</File>
<File
RelativePath=".\lang\polish.txt">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCustomBuildTool"
Description="Generating polish language file"
CommandLine="strgen\debug\strgen.exe &quot;$(InputPath)&quot;"
Outputs="lang\polish.lng"/>
</FileConfiguration>
</File>
<File
RelativePath=".\lang\slovak.txt">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCustomBuildTool"
Description="Generating slovak language file"
CommandLine="strgen\debug\strgen.exe &quot;$(InputPath)&quot;"
Outputs="lang\slovak.lng"/>
</FileConfiguration>
</File>
<File
RelativePath="lang\swedish.txt">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCustomBuildTool"
Description="Generating swedish language file"
CommandLine="strgen\debug\strgen.exe &quot;$(InputPath)&quot;"
Outputs="lang\swedish.lng"/>
</FileConfiguration>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

@ -0,0 +1,451 @@
/* lzoconf.h -- configuration for the LZO real-time data compression library
This file is part of the LZO real-time data compression library.
Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
All Rights Reserved.
The LZO library is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
The LZO library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
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 the LZO library; see the file COPYING.
If not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Markus F.X.J. Oberhumer
<markus@oberhumer.com>
http://www.oberhumer.com/opensource/lzo/
*/
#ifndef __LZOCONF_H
#define __LZOCONF_H
#define LZO_VERSION 0x1080
#define LZO_VERSION_STRING "1.08"
#define LZO_VERSION_DATE "Jul 12 2002"
/* internal Autoconf configuration file - only used when building LZO */
#if defined(LZO_HAVE_CONFIG_H)
# include <config.h>
#endif
#include <limits.h>
#ifdef __cplusplus
extern "C" {
#endif
/***********************************************************************
// LZO requires a conforming <limits.h>
************************************************************************/
#if !defined(CHAR_BIT) || (CHAR_BIT != 8)
# error "invalid CHAR_BIT"
#endif
#if !defined(UCHAR_MAX) || !defined(UINT_MAX) || !defined(ULONG_MAX)
# error "check your compiler installation"
#endif
#if (USHRT_MAX < 1) || (UINT_MAX < 1) || (ULONG_MAX < 1)
# error "your limits.h macros are broken"
#endif
/* workaround a cpp bug under hpux 10.20 */
#define LZO_0xffffffffL 4294967295ul
#if !defined(LZO_UINT32_C)
# if (UINT_MAX < LZO_0xffffffffL)
# define LZO_UINT32_C(c) c ## UL
# else
# define LZO_UINT32_C(c) c ## U
# endif
#endif
/***********************************************************************
// architecture defines
************************************************************************/
#if !defined(__LZO_WIN) && !defined(__LZO_DOS) && !defined(__LZO_OS2)
# if defined(__WINDOWS__) || defined(_WINDOWS) || defined(_Windows)
# define __LZO_WIN
# elif defined(__WIN32__) || defined(_WIN32) || defined(WIN32)
# define __LZO_WIN
# elif defined(__NT__) || defined(__NT_DLL__) || defined(__WINDOWS_386__)
# define __LZO_WIN
# elif defined(__DOS__) || defined(__MSDOS__) || defined(MSDOS)
# define __LZO_DOS
# elif defined(__OS2__) || defined(__OS2V2__) || defined(OS2)
# define __LZO_OS2
# elif defined(__palmos__)
# define __LZO_PALMOS
# elif defined(__TOS__) || defined(__atarist__)
# define __LZO_TOS
# endif
#endif
#if (UINT_MAX < LZO_0xffffffffL)
# if defined(__LZO_WIN)
# define __LZO_WIN16
# elif defined(__LZO_DOS)
# define __LZO_DOS16
# elif defined(__LZO_PALMOS)
# define __LZO_PALMOS16
# elif defined(__LZO_TOS)
# define __LZO_TOS16
# elif defined(__C166__)
# else
/* porting hint: for pure 16-bit architectures try compiling
* everything with -D__LZO_STRICT_16BIT */
# error "16-bit target not supported - contact me for porting hints"
# endif
#endif
#if !defined(__LZO_i386)
# if defined(__LZO_DOS) || defined(__LZO_WIN16)
# define __LZO_i386
# elif defined(__i386__) || defined(__386__) || defined(_M_IX86)
# define __LZO_i386
# endif
#endif
#if defined(__LZO_STRICT_16BIT)
# if (UINT_MAX < LZO_0xffffffffL)
# include <lzo16bit.h>
# endif
#endif
/* memory checkers */
#if !defined(__LZO_CHECKER)
# if defined(__BOUNDS_CHECKING_ON)
# define __LZO_CHECKER
# elif defined(__CHECKER__)
# define __LZO_CHECKER
# elif defined(__INSURE__)
# define __LZO_CHECKER
# elif defined(__PURIFY__)
# define __LZO_CHECKER
# endif
#endif
/***********************************************************************
// integral and pointer types
************************************************************************/
/* Integral types with 32 bits or more */
#if !defined(LZO_UINT32_MAX)
# if (UINT_MAX >= LZO_0xffffffffL)
typedef unsigned int lzo_uint32;
typedef int lzo_int32;
# define LZO_UINT32_MAX UINT_MAX
# define LZO_INT32_MAX INT_MAX
# define LZO_INT32_MIN INT_MIN
# elif (ULONG_MAX >= LZO_0xffffffffL)
typedef unsigned long lzo_uint32;
typedef long lzo_int32;
# define LZO_UINT32_MAX ULONG_MAX
# define LZO_INT32_MAX LONG_MAX
# define LZO_INT32_MIN LONG_MIN
# else
# error "lzo_uint32"
# endif
#endif
/* lzo_uint is used like size_t */
#if !defined(LZO_UINT_MAX)
# if (UINT_MAX >= LZO_0xffffffffL)
typedef unsigned int lzo_uint;
typedef int lzo_int;
# define LZO_UINT_MAX UINT_MAX
# define LZO_INT_MAX INT_MAX
# define LZO_INT_MIN INT_MIN
# elif (ULONG_MAX >= LZO_0xffffffffL)
typedef unsigned long lzo_uint;
typedef long lzo_int;
# define LZO_UINT_MAX ULONG_MAX
# define LZO_INT_MAX LONG_MAX
# define LZO_INT_MIN LONG_MIN
# else
# error "lzo_uint"
# endif
#endif
typedef int lzo_bool;
/***********************************************************************
// memory models
************************************************************************/
/* Memory model for the public code segment. */
#if !defined(__LZO_CMODEL)
# if defined(__LZO_DOS16) || defined(__LZO_WIN16)
# define __LZO_CMODEL __far
# elif defined(__LZO_i386) && defined(__WATCOMC__)
# define __LZO_CMODEL __near
# else
# define __LZO_CMODEL
# endif
#endif
/* Memory model for the public data segment. */
#if !defined(__LZO_DMODEL)
# if defined(__LZO_DOS16) || defined(__LZO_WIN16)
# define __LZO_DMODEL __far
# elif defined(__LZO_i386) && defined(__WATCOMC__)
# define __LZO_DMODEL __near
# else
# define __LZO_DMODEL
# endif
#endif
/* Memory model that allows to access memory at offsets of lzo_uint. */
#if !defined(__LZO_MMODEL)
# if (LZO_UINT_MAX <= UINT_MAX)
# define __LZO_MMODEL
# elif defined(__LZO_DOS16) || defined(__LZO_WIN16)
# define __LZO_MMODEL __huge
# define LZO_999_UNSUPPORTED
# elif defined(__LZO_PALMOS16) || defined(__LZO_TOS16)
# define __LZO_MMODEL
# else
# error "__LZO_MMODEL"
# endif
#endif
/* no typedef here because of const-pointer issues */
#define lzo_byte unsigned char __LZO_MMODEL
#define lzo_bytep unsigned char __LZO_MMODEL *
#define lzo_charp char __LZO_MMODEL *
#define lzo_voidp void __LZO_MMODEL *
#define lzo_shortp short __LZO_MMODEL *
#define lzo_ushortp unsigned short __LZO_MMODEL *
#define lzo_uint32p lzo_uint32 __LZO_MMODEL *
#define lzo_int32p lzo_int32 __LZO_MMODEL *
#define lzo_uintp lzo_uint __LZO_MMODEL *
#define lzo_intp lzo_int __LZO_MMODEL *
#define lzo_voidpp lzo_voidp __LZO_MMODEL *
#define lzo_bytepp lzo_bytep __LZO_MMODEL *
#ifndef lzo_sizeof_dict_t
# define lzo_sizeof_dict_t sizeof(lzo_bytep)
#endif
/***********************************************************************
// calling conventions and function types
************************************************************************/
/* linkage */
#if !defined(__LZO_EXTERN_C)
# ifdef __cplusplus
# define __LZO_EXTERN_C extern "C"
# else
# define __LZO_EXTERN_C extern
# endif
#endif
/* calling convention */
#if !defined(__LZO_CDECL)
# if defined(__LZO_DOS16) || defined(__LZO_WIN16)
# define __LZO_CDECL __LZO_CMODEL __cdecl
# elif defined(__LZO_i386) && defined(_MSC_VER)
# define __LZO_CDECL __LZO_CMODEL __cdecl
# elif defined(__LZO_i386) && defined(__WATCOMC__)
# define __LZO_CDECL __LZO_CMODEL __cdecl
# else
# define __LZO_CDECL __LZO_CMODEL
# endif
#endif
#if !defined(__LZO_ENTRY)
# define __LZO_ENTRY __LZO_CDECL
#endif
/* C++ exception specification for extern "C" function types */
#if !defined(__cplusplus)
# undef LZO_NOTHROW
# define LZO_NOTHROW
#elif !defined(LZO_NOTHROW)
# define LZO_NOTHROW
#endif
typedef int
(__LZO_ENTRY *lzo_compress_t) ( const lzo_byte *src, lzo_uint src_len,
lzo_byte *dst, lzo_uintp dst_len,
lzo_voidp wrkmem );
typedef int
(__LZO_ENTRY *lzo_decompress_t) ( const lzo_byte *src, lzo_uint src_len,
lzo_byte *dst, lzo_uintp dst_len,
lzo_voidp wrkmem );
typedef int
(__LZO_ENTRY *lzo_optimize_t) ( lzo_byte *src, lzo_uint src_len,
lzo_byte *dst, lzo_uintp dst_len,
lzo_voidp wrkmem );
typedef int
(__LZO_ENTRY *lzo_compress_dict_t)(const lzo_byte *src, lzo_uint src_len,
lzo_byte *dst, lzo_uintp dst_len,
lzo_voidp wrkmem,
const lzo_byte *dict, lzo_uint dict_len );
typedef int
(__LZO_ENTRY *lzo_decompress_dict_t)(const lzo_byte *src, lzo_uint src_len,
lzo_byte *dst, lzo_uintp dst_len,
lzo_voidp wrkmem,
const lzo_byte *dict, lzo_uint dict_len );
/* assembler versions always use __cdecl */
typedef int
(__LZO_CDECL *lzo_compress_asm_t)( const lzo_byte *src, lzo_uint src_len,
lzo_byte *dst, lzo_uintp dst_len,
lzo_voidp wrkmem );
typedef int
(__LZO_CDECL *lzo_decompress_asm_t)( const lzo_byte *src, lzo_uint src_len,
lzo_byte *dst, lzo_uintp dst_len,
lzo_voidp wrkmem );
/* a progress indicator callback function */
typedef void (__LZO_ENTRY *lzo_progress_callback_t) (lzo_uint, lzo_uint);
/***********************************************************************
// export information
************************************************************************/
/* DLL export information */
#if !defined(__LZO_EXPORT1)
# define __LZO_EXPORT1
#endif
#if !defined(__LZO_EXPORT2)
# define __LZO_EXPORT2
#endif
/* exported calling convention for C functions */
#if !defined(LZO_PUBLIC)
# define LZO_PUBLIC(_rettype) \
__LZO_EXPORT1 _rettype __LZO_EXPORT2 __LZO_ENTRY
#endif
#if !defined(LZO_EXTERN)
# define LZO_EXTERN(_rettype) __LZO_EXTERN_C LZO_PUBLIC(_rettype)
#endif
#if !defined(LZO_PRIVATE)
# define LZO_PRIVATE(_rettype) static _rettype __LZO_ENTRY
#endif
/* exported __cdecl calling convention for assembler functions */
#if !defined(LZO_PUBLIC_CDECL)
# define LZO_PUBLIC_CDECL(_rettype) \
__LZO_EXPORT1 _rettype __LZO_EXPORT2 __LZO_CDECL
#endif
#if !defined(LZO_EXTERN_CDECL)
# define LZO_EXTERN_CDECL(_rettype) __LZO_EXTERN_C LZO_PUBLIC_CDECL(_rettype)
#endif
/* exported global variables (LZO currently uses no static variables and
* is fully thread safe) */
#if !defined(LZO_PUBLIC_VAR)
# define LZO_PUBLIC_VAR(_type) \
__LZO_EXPORT1 _type __LZO_EXPORT2 __LZO_DMODEL
#endif
#if !defined(LZO_EXTERN_VAR)
# define LZO_EXTERN_VAR(_type) extern LZO_PUBLIC_VAR(_type)
#endif
/***********************************************************************
// error codes and prototypes
************************************************************************/
/* Error codes for the compression/decompression functions. Negative
* values are errors, positive values will be used for special but
* normal events.
*/
#define LZO_E_OK 0
#define LZO_E_ERROR (-1)
#define LZO_E_OUT_OF_MEMORY (-2) /* not used right now */
#define LZO_E_NOT_COMPRESSIBLE (-3) /* not used right now */
#define LZO_E_INPUT_OVERRUN (-4)
#define LZO_E_OUTPUT_OVERRUN (-5)
#define LZO_E_LOOKBEHIND_OVERRUN (-6)
#define LZO_E_EOF_NOT_FOUND (-7)
#define LZO_E_INPUT_NOT_CONSUMED (-8)
/* lzo_init() should be the first function you call.
* Check the return code !
*
* lzo_init() is a macro to allow checking that the library and the
* compiler's view of various types are consistent.
*/
#define lzo_init() __lzo_init2(LZO_VERSION,(int)sizeof(short),(int)sizeof(int),\
(int)sizeof(long),(int)sizeof(lzo_uint32),(int)sizeof(lzo_uint),\
(int)lzo_sizeof_dict_t,(int)sizeof(char *),(int)sizeof(lzo_voidp),\
(int)sizeof(lzo_compress_t))
LZO_EXTERN(int) __lzo_init2(unsigned,int,int,int,int,int,int,int,int,int);
/* version functions (useful for shared libraries) */
LZO_EXTERN(unsigned) lzo_version(void);
LZO_EXTERN(const char *) lzo_version_string(void);
LZO_EXTERN(const char *) lzo_version_date(void);
LZO_EXTERN(const lzo_charp) _lzo_version_string(void);
LZO_EXTERN(const lzo_charp) _lzo_version_date(void);
/* string functions */
LZO_EXTERN(int)
lzo_memcmp(const lzo_voidp _s1, const lzo_voidp _s2, lzo_uint _len);
LZO_EXTERN(lzo_voidp)
lzo_memcpy(lzo_voidp _dest, const lzo_voidp _src, lzo_uint _len);
LZO_EXTERN(lzo_voidp)
lzo_memmove(lzo_voidp _dest, const lzo_voidp _src, lzo_uint _len);
LZO_EXTERN(lzo_voidp)
lzo_memset(lzo_voidp _s, int _c, lzo_uint _len);
/* checksum functions */
LZO_EXTERN(lzo_uint32)
lzo_adler32(lzo_uint32 _adler, const lzo_byte *_buf, lzo_uint _len);
LZO_EXTERN(lzo_uint32)
lzo_crc32(lzo_uint32 _c, const lzo_byte *_buf, lzo_uint _len);
/* misc. */
LZO_EXTERN(lzo_bool) lzo_assert(int _expr);
LZO_EXTERN(int) _lzo_config_check(void);
typedef union { lzo_bytep p; lzo_uint u; } __lzo_pu_u;
typedef union { lzo_bytep p; lzo_uint32 u32; } __lzo_pu32_u;
typedef union { void *vp; lzo_bytep bp; lzo_uint32 u32; long l; } lzo_align_t;
/* align a char pointer on a boundary that is a multiple of `size' */
LZO_EXTERN(unsigned) __lzo_align_gap(const lzo_voidp _ptr, lzo_uint _size);
#define LZO_PTR_ALIGN_UP(_ptr,_size) \
((_ptr) + (lzo_uint) __lzo_align_gap((const lzo_voidp)(_ptr),(lzo_uint)(_size)))
/* deprecated - only for backward compatibility */
#define LZO_ALIGN(_ptr,_size) LZO_PTR_ALIGN_UP(_ptr,_size)
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* already included */

@ -0,0 +1,215 @@
#ifndef MACROS_H
#define MACROS_H
#define MAX_INT 0x7FFFFFFF
#ifdef min
#undef min
#endif
#ifdef max
#undef max
#endif
static INLINE int min(int a, int b) { if (a <= b) return a; return b; }
static INLINE int max(int a, int b) { if (a >= b) return a; return b; }
static INLINE uint minu(uint a, uint b) { if (a <= b) return a; return b; }
static INLINE uint maxu(uint a, uint b) { if (a >= b) return a; return b; }
static INLINE int clamp(int a, int min, int max) { if (a <= min) return min; if (a >= max) return max; return a; }
static INLINE int clamp2(int a, int min, int max) { if (a <= min) a=min; if (a >= max) a=max; return a; }
static INLINE bool int32_add_overflow(int32 a, int32 b) { return (int32)(a^b)>=0 && (int32)(a^(a+b))<0; }
static INLINE bool int32_sub_overflow(int32 a, int32 b) { return (int32)(a^b)<0 && (int32)(a^(a-b))<0; }
static INLINE bool str_eq(const byte *a, const byte *b)
{
int i=0;
while (a[i] == b[i]) {
if (a[i] == 0)
return true;
i++;
}
return false;
}
// Will crash if strings are equal
static INLINE bool str_is_below(byte *a, byte *b) {
while (*a <= *b) {
if (*a < *b) return true;
a++;
b++;
}
return false;
}
static INLINE int32 BIGMULSS(int32 a, int32 b, int shift) {
return (int32)(((int64)(a) * (int64)(b)) >> (shift));
}
static INLINE uint32 BIGMULUS(uint32 a, uint32 b, int shift) {
return (uint32)(((uint64)(a) * (uint64)(b)) >> (shift));
}
static INLINE int64 BIGMULS(int32 a, int32 b) {
return (int32)(((int64)(a) * (int64)(b)));
}
/* OPT: optimized into an unsigned comparison */
//#define IS_INSIDE_1D(x, base, size) ((x) >= (base) && (x) < (base) + (size))
#define IS_INSIDE_1D(x, base, size) ( (uint)((x) - (base)) < ((uint)(size)) )
#define TILE_X_BITS 8
#define TILE_Y_BITS 8
#define LANDSCAPE_SIZE_FACTOR 1
#define TILE_FROM_XY(x,y) (int)((((y) >> 4) << TILE_X_BITS) + ((x) >> 4))
#define TILE_XY(x,y) (int)(((y) << TILE_X_BITS) + (x))
#define IS_TILETYPE(_t_, _s_) (_map_type_and_height[(_t_)] >> 4 == (_s_))
#define GET_TILETYPE(_t_) (_map_type_and_height[(_t_)] >> 4)
#define GET_TILEHEIGHT(_t_) ((_map_type_and_height[_t_] & 0xF) * 8)
enum {
CORRECT_Z_BITS = 1 << 1 | 1 << 2 | 1 << 3 | 1 << 4 | 1 << 5 | 1 << 6 | 1 << 7
};
#define CORRECT_Z(tileh) (CORRECT_Z_BITS & (1 << tileh))
#define TILES_X (1 << TILE_X_BITS)
#define TILES_Y (1 << TILE_Y_BITS)
#define TILE_X_MAX (TILES_X-1)
#define TILE_Y_MAX (TILES_Y-1)
#define TILE_ASSERT(x) assert( TILE_MASK(x) == (x) );
extern uint SafeTileAdd(uint x, int add, const char *exp, const char *file, int line);
#if !defined(_DEBUG) || TILE_X_BITS != 8
# define TILE_ADD(x,y) ((x)+(y))
#else
# if defined(__GNUC__)
# define TILE_ADD(x,y) (SafeTileAdd((x),(y), "??", __FILE__, __LINE__))
# else
# define TILE_ADD(x,y) (SafeTileAdd((x),(y), #x ## ", " ## #y, __FILE__, __LINE__))
# endif
#endif
#define TILE_ADDXY(tile, x, y) TILE_ADD(tile, TILE_XY(x,y))
#if TILE_X_BITS == 8
#define GET_TILE_X(t) (uint)((byte)(t))
#define GET_TILE_Y(t) (uint)((t) >> 8)
#define TILE_MASK(x) ((uint16)(x))
#else
#define GET_TILE_X(t) (uint)((t) & ((1 << TILE_X_BITS)-1))
#define GET_TILE_Y(t) (uint)((t) >> TILE_X_BITS)
#define TILE_MASK(x) (int)((x) & ((1 << (TILE_X_BITS + TILE_Y_BITS))-1))
#endif
//#define REMADP_COORDS(x,y,z) { int t = x; x = (y-t)*2; y+=t-z; }
#define PACK_POINT(x,y) ((x) | ((y) << 16))
#define UNPACK_POINT_X(p) ((uint16)(p))
#define UNPACK_POINT_Y(p) ((uint16)(p>>16))
#define PACK_PPOINT(p) PACK_POINT((p).x, (p).y)
#define HASBIT(x,y) ((x) & (1 << (y)))
#define SETBIT(x,y) ((x) |= (1 << (y)))
#define CLRBIT(x,y) ((x) &= ~(1 << (y)))
// checking more bits. Maybe unneccessary, but easy to use
#define HASBITS(x,y) ((x) & (y))
#define SETBITS(x,y) ((x) |= (y))
#define CLRBITS(x,y) ((x) &= ~(y))
#define PLAYER_SPRITE_COLOR(owner) ((_player_colors[owner] << 16) + 0x3070000)
#define SPRITE_PALETTE(x) ((x) + 0x8000)
extern const byte _ffb_64[128];
#define FIND_FIRST_BIT(x) _ffb_64[(x)]
#define KILL_FIRST_BIT(x) _ffb_64[(x)+64]
static INLINE int FindFirstBit2x64(int value)
{
int i = 0;
if ( (byte) value == 0) {
i += 8;
value >>= 8;
}
return i + FIND_FIRST_BIT(value & 0x3F);
}
#if TILE_X_BITS + TILE_Y_BITS <= 16
typedef uint16 TileIndex;
typedef int16 TileIndexDiff;
#else
typedef uint32 TileIndex;
typedef int32 TileIndexDiff;
#endif
/* [min,max), strictly less than */
#define IS_BYTE_INSIDE(a,min,max) ((byte)((a)-(min)) < (byte)((max)-(min)))
#define IS_INT_INSIDE(a,min,max) ((uint)((a)-(min)) < (uint)((max)-(min)))
#define CHANCE16(a,b) ((uint16)Random() <= (uint16)((65536 * a) / b))
#define CHANCE16R(a,b,r) ((uint16)(r=Random()) <= (uint16)((65536 * a) / b))
#define CHANCE16I(a,b,v) ((uint16)(v) <= (uint16)((65536 * a) / b))
#define BEGIN_TILE_LOOP(var,w,h,tile) \
{int h_cur = h; \
uint var = tile; \
do { \
int w_cur = w; \
do {
#define END_TILE_LOOP(var,w,h,tile) \
} while (++var, --w_cur != 0); \
} while (var += TILE_XY(0,1) - (w), --h_cur != 0);}
#define for_each_bit(_i,_b) \
for(_i=0; _b!=0; _i++,_b>>=1) \
if (_b&1)
#define assert_array(i,j) assert(i < lengthof(j))
#define abs myabs
static INLINE int intxchg_(int *a, int b) { int t = *a; *a = b; return t; }
#define intxchg(a,b) intxchg_(&(a), (b))
#define intswap(a,b) ((b) = intxchg_(&(a), (b)))
static INLINE int myabs(int a) { if (a<0) a = -a; return a; }
static INLINE void swap_byte(byte *a, byte *b) { byte t = *a; *a = *b; *b = t; }
static INLINE void swap_uint16(uint16 *a, uint16 *b) { uint16 t = *a; *a = *b; *b = t; }
static INLINE void swap_int16(int16 *a, int16 *b) { int16 t = *a; *a = *b; *b = t; }
static INLINE void swap_tile(TileIndex *a, TileIndex *b) { TileIndex t = *a; *a = *b; *b = t; }
#if defined(TTD_LITTLE_ENDIAN)
# define READ_LE_UINT16(b) (*(uint16*)(b))
# define ADD_WORD(x) (x)&0xFF, ((x) >> 8)&0xFF
# define ADD_DWORD(x) (x)&0xFF, ((x) >> 8)&0xFF, ((x) >> 16)&0xFF, ((x) >> 24)&0xFF
#elif defined(TTD_BIG_ENDIAN)
static INLINE uint16 READ_LE_UINT16(const void *b) {
return ((byte*)b)[0] + (((byte*)b)[1] << 8);
}
# define ADD_WORD(x) ((x) >> 8)&0xFF, (x)&0xFF
# define ADD_DWORD(x) ((x) >> 24)&0xFF, ((x) >> 16)&0xFF, ((x) >> 8)&0xFF, (x)&0xFF
#endif
static INLINE void WRITE_LE_UINT16(const void *b, uint16 x) {
((byte*)b)[0] = (byte)x;
((byte*)b)[1] = (byte)(x >> 8);
}
#endif /* MACROS_H */

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 766 B

@ -0,0 +1,81 @@
# This file generates Makefile.config
# Create default config from autodetected values
# Magic at work, note that you can't use commas in arguments for this
CONFIG_LINE=@$(SHELL) -c 'echo $(1)' >> $(MAKE_CONFIG) 2> /dev/null
$(MAKE_CONFIG):
touch $(MAKE_CONFIG)
$(call CONFIG_LINE,\# OpenTTD config file for makefile)
$(call CONFIG_LINE,\# Set your options here - 1 for use and empty for disable)
$(call CONFIG_LINE,)
$(call CONFIG_LINE,\# User setup flags)
$(call CONFIG_LINE,\# Translator: adds TODO to any untranslated strings)
$(call CONFIG_LINE,\# Display_Warnings: when off it hides some warnings while compiling)
$(call CONFIG_LINE,\# MIDI: sets path to midi player)
$(call CONFIG_LINE,\# MIDI_ARG: sets an argument which is used when calling the midi player. Default off)
$(call CONFIG_LINE,STATIC:=$(STATIC))
$(call CONFIG_LINE,TRANSLATOR:=$(TRANSLATOR))
$(call CONFIG_LINE,DISPLAY_WARNINGS:=$(DISPLAY_WARNINGS))
$(call CONFIG_LINE,DEBUG:=$(DEBUG))
$(call CONFIG_LINE,PROFILE:=$(PROFILE))
$(call CONFIG_LINE,MIDI:=$(MIDI))
$(call CONFIG_LINE,MIDI_ARG:=$(MIDI_ARG))
$(call CONFIG_LINE,)
$(call CONFIG_LINE,\# DATA_DIR_PREFIX is the path to OpenTTD. It can be absolute or relative)
$(call CONFIG_LINE,\# USE_HOMEDIR sets \~/ in front of DATA_DIR_PREFIX so it uses the homedir)
$(call CONFIG_LINE,\# do not type \~/ yourself because that will not work)
$(call CONFIG_LINE,\# Folders should end with /)
$(call CONFIG_LINE,BINARY_DIR:=$(BINARY_DIR))
$(call CONFIG_LINE,INSTALL_DIR:=$(INSTALL_DIR))
$(call CONFIG_LINE,USE_HOMEDIR:=$(USE_HOMEDIR))
$(call CONFIG_LINE,GAME_DATA_DIR:=$(GAME_DATA_DIR))
$(call CONFIG_LINE,PERSONAL_DIR:=$(PERSONAL_DIR))
$(call CONFIG_LINE,)
$(call CONFIG_LINE,\# Experimental)
$(call CONFIG_LINE,WITH_NETWORK:=$(WITH_NETWORK))
$(call CONFIG_LINE,WITH_DIRECTMUSIC:=$(WITH_DIRECTMUSIC))
$(call CONFIG_LINE,)
$(call CONFIG_LINE,)
$(call CONFIG_LINE,\# Flag to skip test for OS when building static)
$(call CONFIG_LINE,\# OpenTTD have only been succesfully tested with static builds on MorphOS and MacOSX)
$(call CONFIG_LINE,\# If you want to try anyway on other OSes, set this flag)
$(call CONFIG_LINE,\# Inform us if you have success)
$(call CONFIG_LINE,SKIP_STATIC_CHECK:=$(SKIP_STATIC_CHECK))
$(call CONFIG_LINE,)
$(call CONFIG_LINE,)
$(call CONFIG_LINE,\# Everything below this line is autogenerated)
$(call CONFIG_LINE,\#)
$(call CONFIG_LINE,\# If you need to change anything below, you should run "make upgradeconf")
$(call CONFIG_LINE,\# If that does not fix the problem, you should make a bug report.)
$(call CONFIG_LINE,\# It would really help if you could tell how to autodetect the missing setting)
$(call CONFIG_LINE,\# That info could be where the missing lib is placed)
$(call CONFIG_LINE,)
$(call CONFIG_LINE,\# Libs)
$(call CONFIG_LINE,WITH_ZLIB:=$(WITH_ZLIB))
$(call CONFIG_LINE,WITH_SDL:=$(WITH_SDL))
$(call CONFIG_LINE,WITH_PNG:=$(WITH_PNG))
$(call CONFIG_LINE,STATIC_ZLIB_PATH:=$(STATIC_ZLIB_PATH))
$(call CONFIG_LINE,)
$(call CONFIG_LINE,\# OS flags)
$(call CONFIG_LINE,WIN32:=$(WIN32))
$(call CONFIG_LINE,UNIX:=$(UNIX))
$(call CONFIG_LINE,OSX:=$(OSX))
$(call CONFIG_LINE,FREEBSD:=$(FREEBSD))
$(call CONFIG_LINE,MORPHOS:=$(MORPHOS))
$(call CONFIG_LINE,CYGWIN:=$(CYGWIN))
$(call CONFIG_LINE,MINGW:=$(MINGW))
$(call CONFIG_LINE,)
$(call CONFIG_LINE,\# misc)
$(call CONFIG_LINE,SDL-CONFIG:=$(SDL-CONFIG))
$(call CONFIG_LINE,CONFIG_INCLUDED:=yes)
$(call CONFIG_LINE,PATH_SET:=$(PATH_SET))

@ -0,0 +1,80 @@
# this file detects what OS and libs the computer have/are running
# Automatically recognize if building on Win32
ifdef WINDIR
ifndef UNIX
WIN32:=1
endif
else
UNIX:=1
endif
# Automatically recognize if building on FreeBSD
ifeq ($(shell uname),FreeBSD)
FREEBSD:=1
endif
# Automatically recognize if building on MacOSX
ifeq ($(VENDOR), apple)
OSX:=1
# OSX uses the unix setup too
UNIX:=1
endif
# Automatically recognize if building on MorphOS
ifeq ($(shell uname), MorphOS)
MORPHOS:=1
# MorphOS uses UNIX setup too
UNIX:=1
endif
# FreeBSD uses sdl11 instead of sdl
ifdef FREEBSD
SDL-CONFIG:=sdl11-config
else
SDL-CONFIG:=sdl-config
endif
# Library detections
WITH_SDL:=$(shell $(SDL-CONFIG) --version 2>/dev/null)
# libpng detection
ifdef FREEBSD
# a little hack was needed for FreeBSD because it misses libpng-config
WITH_PNG:=$(shell ls /usr/lib | grep "libpng" 2>/dev/null) $(shell \
ls /usr/local/lib | grep "libpng" 2>/dev/null)
ifdef WITH_PNG
# makes the flag look nicer in makefile.config
WITH_PNG:=1
endif
else
WITH_PNG:=$(shell libpng-config --version 2>/dev/null)
endif
ifdef WITH_PNG
# LibPNG depends on Zlib
WITH_ZLIB:=1
else
# We go looking for zlib with a little hack
WITH_ZLIB:=$(shell ls /usr/include | grep "zlib.h" 2>/dev/null) \
$(shell ls /usr/local/include | grep "zlib.h" 2>/dev/null)
ifdef WITH_ZLIB
WITH_ZLIB:=1
endif
endif
# sets the default paths
ifdef UNIX
ifndef OSX
ifndef MORPHOS
ifndef BIN_DIR
#BINARY_DIR:=
#DATA_DIR_PREFIX:=
#INSTALL_DIR:=/usr/local/
#USE_HOMEDIR:=
endif
endif
endif
endif

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

File diff suppressed because it is too large Load Diff

@ -0,0 +1,100 @@
/* minilzo.h -- mini subset of the LZO real-time data compression library
This file is part of the LZO real-time data compression library.
Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
All Rights Reserved.
The LZO library is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
The LZO library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
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 the LZO library; see the file COPYING.
If not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Markus F.X.J. Oberhumer
<markus@oberhumer.com>
http://www.oberhumer.com/opensource/lzo/
*/
/*
* NOTE:
* the full LZO package can be found at
* http://www.oberhumer.com/opensource/lzo/
*/
#ifndef __MINILZO_H
#define __MINILZO_H
#define MINILZO_VERSION 0x1080
#ifdef __LZOCONF_H
# error "you cannot use both LZO and miniLZO"
#endif
#undef LZO_HAVE_CONFIG_H
#include "lzoconf.h"
#if !defined(LZO_VERSION) || (LZO_VERSION != MINILZO_VERSION)
# error "version mismatch in header files"
#endif
#ifdef __cplusplus
extern "C" {
#endif
/***********************************************************************
//
************************************************************************/
/* Memory required for the wrkmem parameter.
* When the required size is 0, you can also pass a NULL pointer.
*/
#define LZO1X_MEM_COMPRESS LZO1X_1_MEM_COMPRESS
#define LZO1X_1_MEM_COMPRESS ((lzo_uint32) (16384L * lzo_sizeof_dict_t))
#define LZO1X_MEM_DECOMPRESS (0)
/* compression */
LZO_EXTERN(int)
lzo1x_1_compress ( const lzo_byte *src, lzo_uint src_len,
lzo_byte *dst, lzo_uintp dst_len,
lzo_voidp wrkmem );
/* decompression */
LZO_EXTERN(int)
lzo1x_decompress ( const lzo_byte *src, lzo_uint src_len,
lzo_byte *dst, lzo_uintp dst_len,
lzo_voidp wrkmem /* NOT USED */ );
/* safe decompression with overrun testing */
LZO_EXTERN(int)
lzo1x_decompress_safe ( const lzo_byte *src, lzo_uint src_len,
lzo_byte *dst, lzo_uintp dst_len,
lzo_voidp wrkmem /* NOT USED */ );
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* already included */

785
misc.c

@ -0,0 +1,785 @@
#include "stdafx.h"
#include "ttd.h"
#include "vehicle.h"
#include "gfx.h"
#include "assert.h"
#include "saveload.h"
extern void StartupEconomy();
extern void InitNewsItemStructs();
static uint32 _random_seed_3, _random_seed_4;
byte _name_array[512][32];
static INLINE uint32 ROR(uint32 x, int n)
{
return (x >> n) + (x << ((sizeof(x)*8)-n));
}
uint32 Random()
{
uint32 t = _random_seed_2;
uint32 s = _random_seed_1;
_random_seed_1 = s + ROR(t ^ 0x1234567F, 7);
return _random_seed_2 = ROR(s, 3);
}
uint RandomRange(uint max)
{
return (uint16)Random() * max >> 16;
}
uint32 InteractiveRandom()
{
uint32 t = _random_seed_4;
uint32 s = _random_seed_3;
_random_seed_3 = s + ROR(t ^ 0x1234567F, 7);
return _random_seed_4 = ROR(s, 3);
}
void memswap(void *a, void *b, size_t size) {
void *c = alloca(size);
memcpy(c, a, size);
memcpy(a, b, size);
memcpy(b, c, size);
}
void SetDate(uint date)
{
YearMonthDay ymd;
ConvertDayToYMD(&ymd, _date = date);
_cur_year = ymd.year;
_cur_month = ymd.month;
}
void InitializeClearLand();
void InitializeRail();
void InitializeRailGui();
void InitializeRoad();
void InitializeRoadGui();
void InitializeAirportGui();
void InitializeDock();
void InitializeDockGui();
void InitializeIndustries();
void InitializeLandscape();
void InitializeTowns();
void InitializeTrees();
void InitializeStations();
void InitializeNameMgr();
void InitializePlayers();
void InitializeCheats();
void GenerateLandscape();
void GenerateClearTile();
void GenerateIndustries();
void GenerateUnmovables();
void GenerateTowns();
void StartupPlayers();
void StartupEngines();
void StartupDisasters();
void GenerateTrees();
void ConvertGroundTilesIntoWaterTiles();
void InitializeGame()
{
SetObjectToPlace(1, 0, 0, 0);
_pause = 0;
_fast_forward = 0;
_tick_counter = 0;
_date_fract = 0;
_cur_tileloop_tile = 0;
_vehicle_id_ctr_day = 0;
{
uint starting = ConvertIntDate(_patches.starting_date);
if ( starting == (uint)-1) starting = 10958;
SetDate(starting);
}
InitializeVehicles();
_backup_orders_tile = 0;
InitNewsItemStructs();
InitializeLandscape();
InitializeClearLand();
InitializeRail();
InitializeRailGui();
InitializeRoad();
InitializeRoadGui();
InitializeAirportGui();
InitializeDock();
InitializeDockGui();
InitializeTowns();
InitializeTrees();
InitializeStations();
InitializeIndustries();
InitializeNameMgr();
InitializeTrains();
InitializePlayers();
InitializeCheats();
InitTextEffects();
InitializeAnimatedTiles();
InitializeLandscapeVariables(false);
ResetObjectToPlace();
}
void GenerateWorld(int mode)
{
int i;
_generating_world = true;
InitializeGame();
SetObjectToPlace(1, 0, 0, 0);
// Must start economy early because of the costs.
StartupEconomy();
// Don't generate landscape items when in the scenario editor.
if (mode == 1) {
// empty world in scenario editor
ConvertGroundTilesIntoWaterTiles();
} else {
GenerateLandscape();
GenerateClearTile();
// only generate towns, tree and industries in newgame mode.
if (mode == 0) {
GenerateTowns();
GenerateTrees();
GenerateIndustries();
GenerateUnmovables();
}
}
// These are probably pointless when inside the scenario editor.
StartupPlayers();
StartupEngines();
StartupDisasters();
_generating_world = false;
// No need to run the tile loop in the scenario editor.
if (mode != 1) {
for(i=0x500; i!=0; i--)
RunTileLoop();
}
ResetObjectToPlace();
}
void DeleteName(StringID id)
{
if ((id & 0xF800) == 0x7800) {
memset(_name_array[id & 0x1FF], 0, sizeof(_name_array[id & 0x1FF]));
}
}
byte *GetName(int id, byte *buff)
{
byte *b;
if (id & 0x600) {
if (id & 0x200) {
if (id & 0x400) {
GetParamInt32();
GetParamUint16();
} else {
GetParamUint16();
}
} else {
GetParamInt32();
}
}
b = _name_array[(id&~0x600)];
while ((*buff++ = *b++) != 0);
return buff - 1;
}
void InitializeCheats()
{
memset(&_cheats, 0, sizeof(Cheats));
}
void InitializeNameMgr()
{
memset(_name_array, 0, sizeof(_name_array));
}
StringID AllocateName(const byte *name, byte skip)
{
int free_item = -1;
const byte *names;
byte *dst;
int i;
names = &_name_array[0][0];
for(i=0; i!=512; i++,names+=sizeof(_name_array[0])) {
if (names[0] == 0) {
if (free_item == -1)
free_item = i;
} else {
if (str_eq(names, name)) {
_error_message = STR_0132_CHOSEN_NAME_IN_USE_ALREADY;
return 0;
}
}
}
if (free_item < 0) {
_error_message = STR_0131_TOO_MANY_NAMES_DEFINED;
return 0;
}
dst=_name_array[free_item];
for(i=0; (dst[i] = name[i]) != 0 && ++i != 32; ) {}
dst[31] = 0;
return free_item | 0x7800 | (skip << 8);
}
const TileIndexDiff _tileoffs_by_dir[4] = {
TILE_XY(-1, 0),
TILE_XY(0, 1),
TILE_XY(1, 0),
TILE_XY(0, -1),
};
#define M(a,b) ((a<<5)|b)
static const uint16 _month_date_from_year_day[] = {
M(0,1),M(0,2),M(0,3),M(0,4),M(0,5),M(0,6),M(0,7),M(0,8),M(0,9),M(0,10),M(0,11),M(0,12),M(0,13),M(0,14),M(0,15),M(0,16),M(0,17),M(0,18),M(0,19),M(0,20),M(0,21),M(0,22),M(0,23),M(0,24),M(0,25),M(0,26),M(0,27),M(0,28),M(0,29),M(0,30),M(0,31),
M(1,1),M(1,2),M(1,3),M(1,4),M(1,5),M(1,6),M(1,7),M(1,8),M(1,9),M(1,10),M(1,11),M(1,12),M(1,13),M(1,14),M(1,15),M(1,16),M(1,17),M(1,18),M(1,19),M(1,20),M(1,21),M(1,22),M(1,23),M(1,24),M(1,25),M(1,26),M(1,27),M(1,28),M(1,29),
M(2,1),M(2,2),M(2,3),M(2,4),M(2,5),M(2,6),M(2,7),M(2,8),M(2,9),M(2,10),M(2,11),M(2,12),M(2,13),M(2,14),M(2,15),M(2,16),M(2,17),M(2,18),M(2,19),M(2,20),M(2,21),M(2,22),M(2,23),M(2,24),M(2,25),M(2,26),M(2,27),M(2,28),M(2,29),M(2,30),M(2,31),
M(3,1),M(3,2),M(3,3),M(3,4),M(3,5),M(3,6),M(3,7),M(3,8),M(3,9),M(3,10),M(3,11),M(3,12),M(3,13),M(3,14),M(3,15),M(3,16),M(3,17),M(3,18),M(3,19),M(3,20),M(3,21),M(3,22),M(3,23),M(3,24),M(3,25),M(3,26),M(3,27),M(3,28),M(3,29),M(3,30),
M(4,1),M(4,2),M(4,3),M(4,4),M(4,5),M(4,6),M(4,7),M(4,8),M(4,9),M(4,10),M(4,11),M(4,12),M(4,13),M(4,14),M(4,15),M(4,16),M(4,17),M(4,18),M(4,19),M(4,20),M(4,21),M(4,22),M(4,23),M(4,24),M(4,25),M(4,26),M(4,27),M(4,28),M(4,29),M(4,30),M(4,31),
M(5,1),M(5,2),M(5,3),M(5,4),M(5,5),M(5,6),M(5,7),M(5,8),M(5,9),M(5,10),M(5,11),M(5,12),M(5,13),M(5,14),M(5,15),M(5,16),M(5,17),M(5,18),M(5,19),M(5,20),M(5,21),M(5,22),M(5,23),M(5,24),M(5,25),M(5,26),M(5,27),M(5,28),M(5,29),M(5,30),
M(6,1),M(6,2),M(6,3),M(6,4),M(6,5),M(6,6),M(6,7),M(6,8),M(6,9),M(6,10),M(6,11),M(6,12),M(6,13),M(6,14),M(6,15),M(6,16),M(6,17),M(6,18),M(6,19),M(6,20),M(6,21),M(6,22),M(6,23),M(6,24),M(6,25),M(6,26),M(6,27),M(6,28),M(6,29),M(6,30),M(6,31),
M(7,1),M(7,2),M(7,3),M(7,4),M(7,5),M(7,6),M(7,7),M(7,8),M(7,9),M(7,10),M(7,11),M(7,12),M(7,13),M(7,14),M(7,15),M(7,16),M(7,17),M(7,18),M(7,19),M(7,20),M(7,21),M(7,22),M(7,23),M(7,24),M(7,25),M(7,26),M(7,27),M(7,28),M(7,29),M(7,30),M(7,31),
M(8,1),M(8,2),M(8,3),M(8,4),M(8,5),M(8,6),M(8,7),M(8,8),M(8,9),M(8,10),M(8,11),M(8,12),M(8,13),M(8,14),M(8,15),M(8,16),M(8,17),M(8,18),M(8,19),M(8,20),M(8,21),M(8,22),M(8,23),M(8,24),M(8,25),M(8,26),M(8,27),M(8,28),M(8,29),M(8,30),
M(9,1),M(9,2),M(9,3),M(9,4),M(9,5),M(9,6),M(9,7),M(9,8),M(9,9),M(9,10),M(9,11),M(9,12),M(9,13),M(9,14),M(9,15),M(9,16),M(9,17),M(9,18),M(9,19),M(9,20),M(9,21),M(9,22),M(9,23),M(9,24),M(9,25),M(9,26),M(9,27),M(9,28),M(9,29),M(9,30),M(9,31),
M(10,1),M(10,2),M(10,3),M(10,4),M(10,5),M(10,6),M(10,7),M(10,8),M(10,9),M(10,10),M(10,11),M(10,12),M(10,13),M(10,14),M(10,15),M(10,16),M(10,17),M(10,18),M(10,19),M(10,20),M(10,21),M(10,22),M(10,23),M(10,24),M(10,25),M(10,26),M(10,27),M(10,28),M(10,29),M(10,30),
M(11,1),M(11,2),M(11,3),M(11,4),M(11,5),M(11,6),M(11,7),M(11,8),M(11,9),M(11,10),M(11,11),M(11,12),M(11,13),M(11,14),M(11,15),M(11,16),M(11,17),M(11,18),M(11,19),M(11,20),M(11,21),M(11,22),M(11,23),M(11,24),M(11,25),M(11,26),M(11,27),M(11,28),M(11,29),M(11,30),M(11,31),
};
#undef M
enum {
ACCUM_JAN = 0,
ACCUM_FEB = ACCUM_JAN + 31,
ACCUM_MAR = ACCUM_FEB + 29,
ACCUM_APR = ACCUM_MAR + 31,
ACCUM_MAY = ACCUM_APR + 30,
ACCUM_JUN = ACCUM_MAY + 31,
ACCUM_JUL = ACCUM_JUN + 30,
ACCUM_AUG = ACCUM_JUL + 31,
ACCUM_SEP = ACCUM_AUG + 31,
ACCUM_OCT = ACCUM_SEP + 30,
ACCUM_NOV = ACCUM_OCT + 31,
ACCUM_DEC = ACCUM_NOV + 30,
};
static const uint16 _accum_days_for_month[] = {
ACCUM_JAN,ACCUM_FEB,ACCUM_MAR,ACCUM_APR,
ACCUM_MAY,ACCUM_JUN,ACCUM_JUL,ACCUM_AUG,
ACCUM_SEP,ACCUM_OCT,ACCUM_NOV,ACCUM_DEC,
};
void ConvertDayToYMD(YearMonthDay *ymd, uint16 date)
{
uint yr = date / (365+365+365+366);
uint rem = date % (365+365+365+366);
uint x;
yr *= 4;
if (rem >= 366) {
rem--;
do {
rem -= 365;
yr++;
} while (rem >= 365);
if (rem >= 31+28) rem++;
}
ymd->year = yr;
x = _month_date_from_year_day[rem];
ymd->month = x >> 5;
ymd->day = x & 0x1F;
}
// year is a number between 0..?
// month is a number between 0..11
// day is a number between 1..31
uint ConvertYMDToDay(uint year, uint month, uint day)
{
uint rem;
// day in the year
rem = _accum_days_for_month[month] + day - 1;
// remove feb 29 from year 1,2,3
if (year & 3) rem += (year & 3) * 365 + (rem < 31+29);
// base date.
return (year >> 2) * (365+365+365+366) + rem;
}
// convert a date on the form
// 1920 - 2090
// 192001 - 209012
// 19200101 - 20901231
// or if > 2090 and below 65536, treat it as a daycount
// returns -1 if no conversion was possible
uint ConvertIntDate(uint date)
{
uint year, month = 0, day = 1;
if (IS_INT_INSIDE(date, 1920, 2090 + 1)) {
year = date - 1920;
} else if (IS_INT_INSIDE(date, 192001, 209012+1)) {
month = date % 100 - 1;
year = date / 100 - 1920;
} else if (IS_INT_INSIDE(date, 19200101, 20901231+1)) {
day = date % 100; date /= 100;
month = date % 100 - 1;
year = date / 100 - 1920;
} else if (IS_INT_INSIDE(date, 2091, 65536))
return date;
else
return (uint)-1;
// invalid ranges?
if (month >= 12 || !IS_INT_INSIDE(day, 1, 31+1)) return (uint)-1;
return ConvertYMDToDay(year, month, day);
}
typedef struct LandscapePredefVar {
StringID names[NUM_CARGO];
byte weights[NUM_CARGO];
StringID sprites[NUM_CARGO];
uint16 initial_cargo_payment[NUM_CARGO];
byte transit_days_table_1[NUM_CARGO];
byte transit_days_table_2[NUM_CARGO];
byte railwagon_by_cargo[3][NUM_CARGO];
byte road_veh_by_cargo_start[NUM_CARGO];
byte road_veh_by_cargo_count[NUM_CARGO];
} LandscapePredefVar;
#include "table/landscape_const.h"
// Calculate constants that depend on the landscape type.
void InitializeLandscapeVariables(bool only_constants)
{
const LandscapePredefVar *lpd;
int i;
StringID str;
lpd = &_landscape_predef_var[_opt.landscape];
memcpy(_cargoc.ai_railwagon, lpd->railwagon_by_cargo, sizeof(lpd->railwagon_by_cargo));
memcpy(_cargoc.ai_roadveh_start, lpd->road_veh_by_cargo_start,sizeof(lpd->road_veh_by_cargo_start));
memcpy(_cargoc.ai_roadveh_count, lpd->road_veh_by_cargo_count,sizeof(lpd->road_veh_by_cargo_count));
for(i=0; i!=NUM_CARGO; i++) {
_cargoc.sprites[i] = lpd->sprites[i];
str = lpd->names[i];
_cargoc.names_s[i] = str;
_cargoc.names_p[i] = (str += 0x20);
_cargoc.names_long_s[i] = (str += 0x20);
_cargoc.names_long_p[i] = (str += 0x20);
_cargoc.names_short[i] = (str += 0x20);
_cargoc.weights[i] = lpd->weights[i];
if (!only_constants) {
_cargo_payment_rates[i] = lpd->initial_cargo_payment[i];
_cargo_payment_rates_frac[i] = 0;
}
_cargoc.transit_days_1[i] = lpd->transit_days_table_1[i];
_cargoc.transit_days_2[i] = lpd->transit_days_table_2[i];
}
}
// distance in Manhattan metric
uint GetTileDist(TileIndex xy1, TileIndex xy2)
{
return myabs(GET_TILE_X(xy1) - GET_TILE_X(xy2)) +
myabs(GET_TILE_Y(xy1) - GET_TILE_Y(xy2));
}
// maximum distance in x _or_ y
uint GetTileDist1D(TileIndex xy1, TileIndex xy2)
{
return max(myabs(GET_TILE_X(xy1) - GET_TILE_X(xy2)),
myabs(GET_TILE_Y(xy1) - GET_TILE_Y(xy2)));
}
uint GetTileDist1Db(TileIndex xy1, TileIndex xy2)
{
int a = myabs(GET_TILE_X(xy1) - GET_TILE_X(xy2));
int b = myabs(GET_TILE_Y(xy1) - GET_TILE_Y(xy2));
if (a > b)
return a*2+b;
else
return b*2+a;
}
uint GetTileDistAdv(TileIndex xy1, TileIndex xy2)
{
uint a = myabs(GET_TILE_X(xy1) - GET_TILE_X(xy2));
uint b = myabs(GET_TILE_Y(xy1) - GET_TILE_Y(xy2));
return a*a+b*b;
}
bool CheckDistanceFromEdge(TileIndex tile, uint distance)
{
return IS_INT_INSIDE(GET_TILE_X(tile), distance, TILE_X_MAX + 1 - distance) &&
IS_INT_INSIDE(GET_TILE_Y(tile), distance, TILE_Y_MAX + 1 - distance);
}
void OnNewDay_Train(Vehicle *v);
void OnNewDay_RoadVeh(Vehicle *v);
void OnNewDay_Aircraft(Vehicle *v);
void OnNewDay_Ship(Vehicle *v);
void OnNewDay_EffectVehicle(Vehicle *v) { /* empty */ }
void OnNewDay_DisasterVehicle(Vehicle *v);
typedef void OnNewVehicleDayProc(Vehicle *v);
static OnNewVehicleDayProc * _on_new_vehicle_day_proc[] = {
OnNewDay_Train,
OnNewDay_RoadVeh,
OnNewDay_Ship,
OnNewDay_Aircraft,
OnNewDay_EffectVehicle,
OnNewDay_DisasterVehicle,
};
void EnginesDailyLoop();
void DisasterDailyLoop();
void PlayersMonthlyLoop();
void EnginesMonthlyLoop();
void TownsMonthlyLoop();
void IndustryMonthlyLoop();
void StationMonthlyLoop();
void PlayersYearlyLoop();
void TrainsYearlyLoop();
void RoadVehiclesYearlyLoop();
void AircraftYearlyLoop();
void ShipsYearlyLoop();
void CheckpointsDailyLoop();
static const uint16 _autosave_months[] = {
0, // never
0xFFF, // every month
0x249, // every 3 months
0x041, // every 6 months
0x001, // every 12 months
};
void IncreaseDate()
{
int i,ctr,t;
YearMonthDay ymd;
if (_game_mode == GM_MENU) {
_tick_counter++;
return;
}
/*if the day changed, call the vehicle event but only update a part of the vehicles
old max was i!= 12. But with that and a bigger number of vehicles (2560), per day only
a part of it could be done, namely: function called max_size date_fract (uint16) / 885 x 12 ==>
65536 / 885 = 74; 74x12 = 888. So max 888. Any vehicles above that were not _on_new_vehicle_day_proc'd
eg. aged.
So new code updates it for max vehicles.
(NUM_VEHICLES / maximum number of times ctr is incremented before reset ) + 1 (to get last vehicles too)
max size of _date_fract / 885 (added each tick) is number of times before ctr is reset.
Calculation might look complicated, but compiler just replaces it with 35, so that's ok
*/
ctr = _vehicle_id_ctr_day;
for(i=0; i!=(NUM_VEHICLES / ((1<<sizeof(_date_fract)*8) / 885)) + 1 && ctr != lengthof(_vehicles); i++) {
Vehicle *v = &_vehicles[ctr++];
if ((t=v->type) != 0)
_on_new_vehicle_day_proc[t - 0x10](v);
}
_vehicle_id_ctr_day = ctr;
/* increase day, and check if a new day is there? */
_tick_counter++;
if ( (_date_fract += 885) >= 885)
return;
/* yeah, increse day counter and call various daily loops */
_date++;
_vehicle_id_ctr_day = 0;
DisasterDailyLoop();
CheckpointsDailyLoop();
if (_game_mode != GM_MENU) {
InvalidateWindowWidget(WC_STATUS_BAR, 0, 0);
EnginesDailyLoop();
}
/* check if we entered a new month? */
ConvertDayToYMD(&ymd, _date);
if ((byte)ymd.month == _cur_month)
return;
_cur_month = ymd.month;
// printf("Month %d, %X\n", ymd.month, _random_seed_1);
/* yes, call various monthly loops */
if (_game_mode != GM_MENU) {
if (HASBIT(_autosave_months[_opt.autosave], _cur_month)) {
_do_autosave = true;
RedrawAutosave();
}
PlayersMonthlyLoop();
EnginesMonthlyLoop();
TownsMonthlyLoop();
IndustryMonthlyLoop();
StationMonthlyLoop();
}
/* check if we entered a new year? */
if ((byte)ymd.year == _cur_year)
return;
_cur_year = ymd.year;
/* yes, call various yearly loops */
PlayersYearlyLoop();
TrainsYearlyLoop();
RoadVehiclesYearlyLoop();
AircraftYearlyLoop();
ShipsYearlyLoop();
/* check if we reached 2090, that's the maximum year. */
if (_cur_year == 171) {
_cur_year = 170;
_date = 62093;
}
if (_patches.auto_euro)
CheckSwitchToEuro();
/* XXX: check if year 2050 was reached */
}
int FindFirstBit(uint32 x)
{
int i = 0;
assert(x != 0);
for(;!(x&1);i++,x>>=1);
return i;
}
extern uint SafeTileAdd(uint tile, int add, const char *exp, const char *file, int line)
{
int x = GET_TILE_X(tile) + (signed char)(add & 0xFF);
int y = GET_TILE_Y(tile) + ((((0x8080 + add)>>8) & 0xFF) - 0x80);
if (x < 0 || y < 0 || x >= TILES_X || y >= TILES_Y) {
char buf[512];
sprintf(buf, "TILE_ADD(%s) when adding 0x%.4X and %d failed", exp, tile, add);
#if !defined(_DEBUG) || !defined(_MSC_VER)
printf("%s\n", buf);
#else
_assert(buf, (char*)file, line);
#endif
}
assert(TILE_XY(x,y) == TILE_MASK(tile + add));
return TILE_XY(x,y);
}
static void Save_NAME()
{
int i;
byte *b = _name_array[0];
for(i=0; i!=lengthof(_name_array); i++,b+=sizeof(_name_array[0])) {
if (*b) {
SlSetArrayIndex(i);
SlArray(b, strlen(b), SLE_UINT8);
}
}
}
static void Load_NAME()
{
int index;
while ((index = SlIterateArray()) != -1) {
SlArray(_name_array[index],SlGetFieldLength(),SLE_UINT8);
}
}
static const byte _game_opt_desc[] = {
// added a new difficulty option (town attitude) in version 4
SLE_CONDARR(GameOptions,diff, SLE_FILE_I16 | SLE_VAR_I32, 17, 0, 3),
SLE_CONDARR(GameOptions,diff, SLE_FILE_I16 | SLE_VAR_I32, 18, 4, 255),
SLE_VAR(GameOptions,diff_level, SLE_UINT8),
SLE_VAR(GameOptions,currency, SLE_UINT8),
SLE_VAR(GameOptions,kilometers, SLE_UINT8),
SLE_VAR(GameOptions,town_name, SLE_UINT8),
SLE_VAR(GameOptions,landscape, SLE_UINT8),
SLE_VAR(GameOptions,snow_line, SLE_UINT8),
SLE_VAR(GameOptions,autosave, SLE_UINT8),
SLE_VAR(GameOptions,road_side, SLE_UINT8),
SLE_END()
};
// Save load game options
static void SaveLoad_OPTS()
{
SlObject(&_opt, _game_opt_desc);
}
static const SaveLoadGlobVarList _date_desc[] = {
{&_date, SLE_UINT16, 0, 255},
{&_date_fract, SLE_UINT16, 0, 255},
{&_tick_counter, SLE_UINT16, 0, 255},
{&_vehicle_id_ctr_day, SLE_UINT16, 0, 255},
{&_age_cargo_skip_counter, SLE_UINT8, 0, 255},
{&_avail_aircraft, SLE_UINT8, 0, 255},
{&_cur_tileloop_tile, SLE_UINT16, 0, 255},
{&_disaster_delay, SLE_UINT16, 0, 255},
{&_station_tick_ctr, SLE_UINT16, 0, 255},
{&_random_seed_1, SLE_UINT32, 0, 255},
{&_random_seed_2, SLE_UINT32, 0, 255},
{&_cur_town_ctr, SLE_UINT8, 0, 255},
{&_cur_player_tick_index, SLE_FILE_U8 | SLE_VAR_UINT, 0, 255},
{&_next_competitor_start, SLE_FILE_U16 | SLE_VAR_UINT, 0, 255},
{&_trees_tick_ctr, SLE_UINT8, 0, 255},
{&_pause, SLE_UINT8, 4, 255},
{NULL,0}
};
// Save load date related variables as well as persistent tick counters
// XXX: currently some unrelated stuff is just put here
static void SaveLoad_DATE()
{
SlGlobList(_date_desc);
}
static const SaveLoadGlobVarList _view_desc[] = {
{&_saved_scrollpos_x, SLE_FILE_I16 | SLE_VAR_INT, 0, 255},
{&_saved_scrollpos_y, SLE_FILE_I16 | SLE_VAR_INT, 0, 255},
{&_saved_scrollpos_zoom, SLE_UINT8, 0, 255},
{NULL,0}
};
static void SaveLoad_VIEW()
{
SlGlobList(_view_desc);
}
static void SaveLoad_MAPT() {
SlArray(_map_type_and_height, lengthof(_map_type_and_height), SLE_UINT8);
}
static void SaveLoad_MAP2() {
SlArray(_map2, lengthof(_map2), SLE_UINT8);
}
static void SaveLoad_M3LO() {
SlArray(_map3_lo, lengthof(_map3_lo), SLE_UINT8);
}
static void SaveLoad_M3HI() {
SlArray(_map3_hi, lengthof(_map3_hi), SLE_UINT8);
}
static void SaveLoad_MAPO() {
SlArray(_map_owner, lengthof(_map_owner), SLE_UINT8);
}
static void SaveLoad_MAP5() {
SlArray(_map5, lengthof(_map5), SLE_UINT8);
}
static void SaveLoad_MAPE() {
SlArray(_map_extra_bits, lengthof(_map_extra_bits), SLE_UINT8);
}
static void Save_CHTS()
{
byte count = sizeof(_cheats)/sizeof(Cheat);
Cheat* cht = (Cheat*) &_cheats;
Cheat* cht_last = &cht[count];
SlSetLength(count*2);
for(; cht != cht_last; cht++) {
SlWriteByte(cht->been_used);
SlWriteByte(cht->value);
}
}
static void Load_CHTS()
{
Cheat* cht = (Cheat*) &_cheats;
uint count = SlGetFieldLength()/2;
for(; count; count--, cht++)
{
cht->been_used = (byte)SlReadByte();
cht->value = (byte)SlReadByte();
}
}
const ChunkHandler _misc_chunk_handlers[] = {
{ 'MAPT', SaveLoad_MAPT, SaveLoad_MAPT, CH_RIFF },
{ 'MAP2', SaveLoad_MAP2, SaveLoad_MAP2, CH_RIFF },
{ 'M3LO', SaveLoad_M3LO, SaveLoad_M3LO, CH_RIFF },
{ 'M3HI', SaveLoad_M3HI, SaveLoad_M3HI, CH_RIFF },
{ 'MAPO', SaveLoad_MAPO, SaveLoad_MAPO, CH_RIFF },
{ 'MAP5', SaveLoad_MAP5, SaveLoad_MAP5, CH_RIFF },
{ 'MAPE', SaveLoad_MAPE, SaveLoad_MAPE, CH_RIFF },
{ 'NAME', Save_NAME, Load_NAME, CH_ARRAY},
{ 'DATE', SaveLoad_DATE, SaveLoad_DATE, CH_RIFF},
{ 'VIEW', SaveLoad_VIEW, SaveLoad_VIEW, CH_RIFF},
{ 'OPTS', SaveLoad_OPTS, SaveLoad_OPTS, CH_RIFF},
{ 'CHTS', Save_CHTS, Load_CHTS, CH_RIFF | CH_LAST}
};

@ -0,0 +1,325 @@
#include "stdafx.h"
#include "ttd.h"
#include "command.h"
#include "player.h"
#include "gfx.h"
#include "window.h"
#include "saveload.h"
#include "economy.h"
/* p1 = player
p2 = face
*/
int32 CmdSetPlayerFace(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
if (flags & DC_EXEC) {
DEREF_PLAYER(p1)->face = p2;
MarkWholeScreenDirty();
}
return 0;
}
/* p1 = player
* p2 = color
*/
int32 CmdSetPlayerColor(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
Player *p,*pp;
// /* can only set color for itself */
// if ( (byte)p1 != _current_player)
// return CMD_ERROR;
p = DEREF_PLAYER(p1);
/* ensure no dups */
FOR_ALL_PLAYERS(pp) {
if (pp->is_active && pp != p && pp->player_color == (byte)p2)
return CMD_ERROR;
}
if (flags & DC_EXEC) {
_player_colors[p1] = (byte)p2;
p->player_color = (byte)p2;
MarkWholeScreenDirty();
}
return 0;
}
int32 CmdIncreaseLoan(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
Player *p;
int32 size;
if ( (byte)p1 != _current_player)
return CMD_ERROR;
p = DEREF_PLAYER(p1);
if (p->current_loan >= _economy.max_loan) {
SET_DPARAM32(0, _economy.max_loan);
return_cmd_error(STR_702B_MAXIMUM_PERMITTED_LOAN);
}
if (flags & DC_EXEC) {
if (p2)
size = _economy.max_loan - p->current_loan;
else
size = IS_HUMAN_PLAYER((byte)p1) ? 10000 : 50000;
p->money64 += size;
p->current_loan += size;
UpdatePlayerMoney32(p);
InvalidatePlayerWindows(p);
}
return 0;
}
int32 CmdDecreaseLoan(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
Player *p;
int32 size;
if ( (byte)p1 != _current_player)
return CMD_ERROR;
p = DEREF_PLAYER(p1);
if (p->current_loan == 0)
return_cmd_error(STR_702D_LOAN_ALREADY_REPAYED);
size = p->current_loan;
// p2 is true while CTRL is pressed (repay all possible loan, or max money you have)
if (!p2)
size = min(size, IS_HUMAN_PLAYER((byte)p1) ? 10000 : 50000);
else { // only repay in chunks of 10K
size = min(size, p->player_money);
size = max(size, 10000);
size -= size % 10000;
}
if (p->player_money < size) {
SET_DPARAM32(0, size);
return_cmd_error(STR_702E_REQUIRED);
}
if (flags & DC_EXEC) {
p->money64 -= size;
p->current_loan -= size;
UpdatePlayerMoney32(p);
InvalidatePlayerWindows(p);
}
return 0;
}
int32 CmdChangeCompanyName(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
StringID str,old_str;
Player *p;
str = AllocateName((byte*)_decode_parameters, 4);
if (str == 0)
return CMD_ERROR;
if (flags & DC_EXEC) {
p = DEREF_PLAYER(p1);
old_str = p->name_1;
p->name_1 = str;
DeleteName(old_str);
MarkWholeScreenDirty();
} else {
DeleteName(str);
}
return 0;
}
int32 CmdChangePresidentName(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
StringID str,old_str;
Player *p;
str = AllocateName((byte*)_decode_parameters, 4);
if (str == 0)
return CMD_ERROR;
if (flags & DC_EXEC) {
p = DEREF_PLAYER(p1);
old_str = p->president_name_1;
p->president_name_1 = str;
DeleteName(old_str);
if (p->name_1 == STR_SV_UNNAMED) {
byte *s = " Transport";
byte *d = (byte*)_decode_parameters, b;
d--; do d++; while (*d);
do *d++ = b = *s++; while(d != (byte*)endof(_decode_parameters) && b != 0);
DoCommandByTile(0, p1, 0, DC_EXEC, CMD_CHANGE_COMPANY_NAME);
}
MarkWholeScreenDirty();
} else {
DeleteName(str);
}
return 0;
}
static void UpdateSignVirtCoords(SignStruct *ss)
{
Point pt = RemapCoords(ss->x, ss->y, ss->z);
SET_DPARAM16(0, ss->str);
UpdateViewportSignPos(&ss->sign, pt.x, pt.y - 6, STR_2806);
}
void UpdateAllSignVirtCoords()
{
SignStruct *ss;
for(ss=_sign_list; ss != endof(_sign_list); ss++)
if (ss->str != 0)
UpdateSignVirtCoords(ss);
}
static void MarkSignDirty(SignStruct *ss)
{
MarkAllViewportsDirty(
ss->sign.left-6,
ss->sign.top-3,
ss->sign.left+ss->sign.width_1*4+12,
ss->sign.top + 45
);
}
int32 CmdPlaceSign(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
SignStruct *ss;
for(ss=_sign_list; ss != endof(_sign_list); ss++) {
if (ss->str == 0) {
if (flags & DC_EXEC) {
ss->str = STR_280A_SIGN;
ss->x = x;
ss->y = y;
ss->z = GetSlopeZ(x,y);
UpdateSignVirtCoords(ss);
MarkSignDirty(ss);
_new_sign_struct = ss;
}
return 0;
}
}
return_cmd_error(STR_2808_TOO_MANY_SIGNS);
}
// p1 = sign index
// p2: 1 -> remove sign
int32 CmdRenameSign(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
StringID str,old_str;
SignStruct *ss;
if (_decode_parameters[0] != 0 && !p2) {
str = AllocateName((byte*)_decode_parameters, 0);
if (str == 0)
return CMD_ERROR;
if (flags & DC_EXEC) {
ss = &_sign_list[p1];
MarkSignDirty(ss);
DeleteName(ss->str);
ss->str = str;
UpdateSignVirtCoords(ss);
MarkSignDirty(ss);
} else {
DeleteName(str);
}
} else {
if (flags & DC_EXEC) {
ss = &_sign_list[p1];
old_str = ss->str;
ss->str = 0;
DeleteName(old_str);
MarkSignDirty(ss);
}
}
return 0;
}
// p1 = 0 decrease pause counter
// p1 = 1 increase pause counter
int32 CmdPause(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
if (flags & DC_EXEC) {
_pause += p1?1:-1;
if(_pause==(byte)-1) _pause = 0;
InvalidateWindow(WC_STATUS_BAR, 0);
InvalidateWindow(WC_MAIN_TOOLBAR, 0);
}
return 0;
}
int32 CmdResume(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
return 0;
}
int32 CmdMoneyCheat(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
SET_EXPENSES_TYPE(EXPENSES_OTHER);
return (int32)p1;
}
int32 CmdChangeDifficultyLevel(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
if (flags & DC_EXEC) {
if (p1 != (uint32)-1L) {
((int*)&_opt_mod_ptr->diff)[p1] = p2;
_opt_mod_ptr->diff_level = 3;
} else {
_opt_mod_ptr->diff_level = p2;
}
InvalidateWindow(WC_GAME_OPTIONS, 0);
}
return 0;
}
static const byte _sign_desc[] = {
SLE_VAR(SignStruct,str, SLE_UINT16),
SLE_VAR(SignStruct,x, SLE_INT16),
SLE_VAR(SignStruct,y, SLE_INT16),
SLE_VAR(SignStruct,z, SLE_UINT8),
SLE_END()
};
static void Save_SIGN()
{
SignStruct *s;
int i;
for(i=0,s=_sign_list; i!=lengthof(_sign_list); i++,s++) {
if (s->str != 0) {
SlSetArrayIndex(i);
SlObject(s, _sign_desc);
}
}
}
static void Load_SIGN()
{
int index;
while ((index = SlIterateArray()) != -1) {
SlObject(&_sign_list[index], _sign_desc);
}
}
const ChunkHandler _sign_chunk_handlers[] = {
{ 'SIGN', Save_SIGN, Load_SIGN, CH_ARRAY | CH_LAST},
};

File diff suppressed because it is too large Load Diff

@ -0,0 +1,453 @@
#include "stdafx.h"
#include "ttd.h"
#include "window.h"
#include "gui.h"
#include "gfx.h"
#include "sound.h"
#include "hal.h"
#define NUM_SONGS_AVAILABLE 22
static byte _playlist_all[] = {
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,0,
};
static byte _playlist_old_style[] = {
1, 8, 2, 9, 14, 15, 19, 13, 0,
};
static byte _playlist_new_style[] = {
6, 11, 10, 17, 21, 18, 5, 0
};
static byte _playlist_ezy_street[] = {
12, 7, 16, 3, 20, 4, 0
};
static byte * const _playlists[] = {
_playlist_all,
_playlist_old_style,
_playlist_new_style,
_playlist_ezy_street,
msf.custom_1,
msf.custom_2,
};
static void SkipToPrevSong()
{
byte *b = _cur_playlist;
byte *p = b;
byte t;
// empty playlist
if (b[0] == 0)
return;
// find the end
do p++; while (p[0] != 0);
// and copy the bytes
t = *--p;
while (p != b) {
p--;
p[1] = p[0];
}
*b = t;
_song_is_active = false;
}
static void SkipToNextSong()
{
byte *b = _cur_playlist, t;
if ((t=b[0]) != 0) {
while (b[1]) {
b[0] = b[1];
b++;
}
b[0] = t;
}
_song_is_active = false;
}
static void MusicVolumeChanged(byte new_vol)
{
_music_driver->set_volume(new_vol);
}
static void DoPlaySong()
{
char filename[256];
sprintf(filename, "%sgm_tt%.2d.gm", _path.gm_dir, _music_wnd_cursong - 1);
_music_driver->play_song(filename);
}
static void DoStopMusic()
{
_music_driver->stop_song();
}
static void SelectSongToPlay()
{
int i;
memset(_cur_playlist, 0, 33);
strcpy(_cur_playlist, _playlists[msf.playlist]);
if (msf.shuffle) {
i = 500;
do {
uint32 r = InteractiveRandom();
byte *a = &_cur_playlist[r & 0x1F];
byte *b = &_cur_playlist[(r >> 8)&0x1F];
if (*a != 0 && *b != 0) {
byte t = *a;
*a = *b;
*b = t;
}
} while (--i);
}
}
static void StopMusic()
{
_music_wnd_cursong = 0;
DoStopMusic();
_song_is_active = false;
InvalidateWindowWidget(WC_MUSIC_WINDOW, 0, 9);
}
static void PlayPlaylistSong()
{
if (_cur_playlist[0] == 0) {
SelectSongToPlay();
if (_cur_playlist[0] == 0)
return;
}
_music_wnd_cursong = _cur_playlist[0];
DoPlaySong();
_song_is_active = true;
InvalidateWindowWidget(WC_MUSIC_WINDOW, 0, 9);
}
void ResetMusic()
{
_music_wnd_cursong = 1;
DoPlaySong();
}
void MusicLoop()
{
if (!msf.btn_down && _song_is_active) {
StopMusic();
} else if (msf.btn_down && !_song_is_active) {
PlayPlaylistSong();
}
if (_song_is_active == false)
return;
if (!_music_driver->is_song_playing()) {
StopMusic();
SkipToNextSong();
PlayPlaylistSong();
}
}
static void MusicTrackSelectionWndProc(Window *w, WindowEvent *e)
{
switch(e->event) {
case WE_PAINT: {
int y,i;
byte *p;
w->disabled_state = (msf.playlist <= 3) ? (1 << 11) : 0;
w->click_state |= 0x18;
DrawWindowWidgets(w);
GfxFillRect(3, 23, 3+177,23+191,0);
GfxFillRect(251, 23, 251+177,23+191,0);
DrawStringCentered(92, 15, STR_01EE_TRACK_INDEX, 0);
SET_DPARAM16(0, STR_01D5_ALL + msf.playlist);
DrawStringCentered(340, 15, STR_01EF_PROGRAM, 0);
for(i=1; (uint)i <= NUM_SONGS_AVAILABLE; i++) {
SET_DPARAM16(0, i);
SET_DPARAM16(2, i);
SET_DPARAM16(1, SPECSTR_SONGNAME);
DrawString(4, 23+(i-1)*6, (i < 10) ? STR_01EC_0 : STR_01ED, 0);
}
for(i=0; i!=6; i++) {
DrawStringCentered(216, 45 + i*8, STR_01D5_ALL + i, (i==msf.playlist) ? 0xC : 0x10);
}
DrawStringCentered(216, 45+8*6+16, STR_01F0_CLEAR, 0);
DrawStringCentered(216, 45+8*6+16*2, STR_01F1_SAVE, 0);
y = 23;
for(p = _playlists[msf.playlist],i=0; (i=*p) != 0; p++) {
SET_DPARAM16(0, i);
SET_DPARAM16(2, i);
SET_DPARAM16(1, SPECSTR_SONGNAME);
DrawString(252, y, (i < 10) ? STR_01EC_0 : STR_01ED, 0);
y += 6;
}
break;
}
case WE_CLICK:
switch(e->click.widget) {
case 3: { /* add to playlist */
int y = (e->click.pt.y - 23) / 6;
int i;
byte *p;
if (msf.playlist < 4) return;
if ((uint)y >= NUM_SONGS_AVAILABLE) return;
p = _playlists[msf.playlist];
for(i=0; i!=32; i++) {
if (p[i] == 0) {
p[i] = (byte)(y + 1);
p[i+1] = 0;
SetWindowDirty(w);
SelectSongToPlay();
break;
}
}
} break;
case 11: /* clear */
_playlists[msf.playlist][0] = 0;
SetWindowDirty(w);
StopMusic();
SelectSongToPlay();
break;
case 12: /* save */
ShowInfo("MusicTrackSelectionWndProc:save not implemented\n");
break;
case 5: case 6: case 7: case 8: case 9: case 10: /* set playlist */
msf.playlist = e->click.widget - 5;
SetWindowDirty(w);
InvalidateWindow(WC_MUSIC_WINDOW, 0);
StopMusic();
SelectSongToPlay();
break;
}
break;
}
}
static const Widget _music_track_selection_widgets[] = {
{ WWT_TEXTBTN, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, 14, 11, 431, 0, 13, STR_01EB_MUSIC_PROGRAM_SELECTION, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_IMGBTN, 14, 0, 431, 14, 217, 0x0, 0},
{ WWT_IMGBTN, 14, 2, 181, 22, 215, 0x0,STR_01FA_CLICK_ON_MUSIC_TRACK_TO},
{ WWT_IMGBTN, 14, 250, 429, 22, 215, 0x0,STR_01F2_CURRENT_PROGRAM_OF_MUSIC},
{ WWT_PUSHIMGBTN, 14, 186, 245, 44, 51, 0x0,STR_01F3_SELECT_ALL_TRACKS_PROGRAM},
{ WWT_PUSHIMGBTN, 14, 186, 245, 52, 59, 0x0,STR_01F4_SELECT_OLD_STYLE_MUSIC},
{ WWT_PUSHIMGBTN, 14, 186, 245, 60, 67, 0x0,STR_01F5_SELECT_NEW_STYLE_MUSIC},
{ WWT_PUSHIMGBTN, 14, 186, 245, 68, 75, 0x0,STR_0330_SELECT_EZY_STREET_STYLE},
{ WWT_PUSHIMGBTN, 14, 186, 245, 76, 83, 0x0,STR_01F6_SELECT_CUSTOM_1_USER_DEFINED},
{ WWT_PUSHIMGBTN, 14, 186, 245, 84, 91, 0x0,STR_01F7_SELECT_CUSTOM_2_USER_DEFINED},
{ WWT_PUSHIMGBTN, 14, 186, 245, 108, 115, 0x0,STR_01F8_CLEAR_CURRENT_PROGRAM_CUSTOM1},
{ WWT_PUSHIMGBTN, 14, 186, 245, 124, 131, 0x0,STR_01F9_SAVE_MUSIC_SETTINGS_TO},
{ WWT_LAST},
};
static const WindowDesc _music_track_selection_desc = {
104, 131, 432, 218,
WC_MUSIC_TRACK_SELECTION,0,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
_music_track_selection_widgets,
MusicTrackSelectionWndProc
};
static void ShowMusicTrackSelection()
{
AllocateWindowDescFront(&_music_track_selection_desc, 0);
}
static void MusicWindowWndProc(Window *w, WindowEvent *e)
{
switch(e->event) {
case WE_PAINT: {
int i,num;
StringID str;
w->click_state |= 0x280;
DrawWindowWidgets(w);
GfxFillRect(187, 16, 200, 33, 0);
num = 8;
for (i=0; i!=num; i++) {
int color = 0xD0;
if (i > 4) {
color = 0xBF;
if (i > 6) {
color = 0xB8;
}
}
GfxFillRect(187, 33 - i*2, 200, 33 - i*2, color);
}
GfxFillRect(60, 46, 239, 52, 0);
str = STR_01E3;
if (_song_is_active != 0 && _music_wnd_cursong != 0) {
str = STR_01E4_0;
SET_DPARAM8(0, _music_wnd_cursong);
if (_music_wnd_cursong >= 10)
str = STR_01E5;
}
DrawString(62, 46, str, 0);
str = STR_01E6;
if (_song_is_active != 0 && _music_wnd_cursong != 0) {
str = STR_01E7;
SET_DPARAM16(0, SPECSTR_SONGNAME);
SET_DPARAM16(1, _music_wnd_cursong);
}
DrawStringCentered(155, 46, str, 0);
DrawString(60, 38, STR_01E8_TRACK_XTITLE, 0);
for(i=0; i!=6; i++) {
DrawStringCentered(25+i*50, 59, STR_01D5_ALL+i, msf.playlist == i ? 0xC : 0x10);
}
DrawStringCentered(31, 43, STR_01E9_SHUFFLE, (msf.shuffle ? 0xC : 0x10));
DrawStringCentered(269, 43, STR_01EA_PROGRAM, 0);
DrawStringCentered(141, 15, STR_01DB_MUSIC_VOLUME, 0);
DrawStringCentered(141, 29, STR_01DD_MIN_MAX, 0);
DrawStringCentered(247, 15, STR_01DC_EFFECTS_VOLUME, 0);
DrawStringCentered(247, 29, STR_01DD_MIN_MAX, 0);
DrawFrameRect(108, 23, 174, 26, 14, 0x20);
DrawFrameRect(214, 23, 280, 26, 14, 0x20);
DrawFrameRect(108 + (msf.music_vol>>1),
22,
111 + (msf.music_vol>>1),
28,
14,
0);
DrawFrameRect(214 + (msf.effect_vol>>1),
22,
217 + (msf.effect_vol>>1),
28,
14,
0);
} break;
case WE_CLICK:
switch(e->click.widget) {
case 2: // skip to prev
if (!_song_is_active)
return;
SkipToPrevSong();
break;
case 3: // skip to next
if (!_song_is_active)
return;
SkipToNextSong();
break;
case 4: // stop playing
msf.btn_down = false;
break;
case 5: // start playing
msf.btn_down = true;
break;
case 6:{ // volume sliders
byte *vol,new_vol;
int x = e->click.pt.x - 88;
if (x < 0)
return;
vol = &msf.music_vol;
if (x >= 106) {
vol = &msf.effect_vol;
x -= 106;
}
new_vol = min(max(x-21,0)*2,127);
if (new_vol != *vol) {
*vol = new_vol;
if (vol == &msf.music_vol)
MusicVolumeChanged(new_vol);
SetWindowDirty(w);
}
_left_button_clicked = false;
} break;
case 10: //toggle shuffle
msf.shuffle ^= 1;
StopMusic();
SelectSongToPlay();
break;
case 11: //show track selection
ShowMusicTrackSelection();
break;
case 12: case 13: case 14: case 15: case 16: case 17: // playlist
msf.playlist = e->click.widget - 12;
SetWindowDirty(w);
InvalidateWindow(WC_MUSIC_TRACK_SELECTION, 0);
StopMusic();
SelectSongToPlay();
break;
}
break;
case WE_MOUSELOOP:
InvalidateWindowWidget(WC_MUSIC_WINDOW, 0, 7);
break;
}
}
static const Widget _music_window_widgets[] = {
{ WWT_TEXTBTN, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, 14, 11, 299, 0, 13, STR_01D2_JAZZ_JUKEBOX, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PUSHIMGBTN, 14, 0, 21, 14, 35, 0x2C5, STR_01DE_SKIP_TO_PREVIOUS_TRACK},
{ WWT_PUSHIMGBTN, 14, 22, 43, 14, 35, 0x2C6, STR_01DF_SKIP_TO_NEXT_TRACK_IN_SELECTION},
{ WWT_PUSHIMGBTN, 14, 44, 65, 14, 35, 0x2C7, STR_01E0_STOP_PLAYING_MUSIC},
{ WWT_PUSHIMGBTN, 14, 66, 87, 14, 35, 0x2C8, STR_01E1_START_PLAYING_MUSIC},
{ WWT_IMGBTN, 14, 88, 299, 14, 35, 0x0, STR_01E2_DRAG_SLIDERS_TO_SET_MUSIC},
{ WWT_IMGBTN, 14, 186, 201, 15, 34, 0x0},
{ WWT_IMGBTN, 14, 0, 299, 36, 57, 0x0},
{ WWT_IMGBTN, 14, 59, 240, 45, 53, 0x0},
{ WWT_PUSHIMGBTN, 14, 6, 55, 42, 49, 0x0, STR_01FB_TOGGLE_PROGRAM_SHUFFLE},
{ WWT_PUSHIMGBTN, 14, 244, 293, 42, 49, 0x0, STR_01FC_SHOW_MUSIC_TRACK_SELECTION},
{ WWT_PUSHIMGBTN, 14, 0, 49, 58, 65, 0x0, STR_01F3_SELECT_ALL_TRACKS_PROGRAM},
{ WWT_PUSHIMGBTN, 14, 50, 99, 58, 65, 0x0, STR_01F4_SELECT_OLD_STYLE_MUSIC},
{ WWT_PUSHIMGBTN, 14, 100, 149, 58, 65, 0x0, STR_01F5_SELECT_NEW_STYLE_MUSIC},
{ WWT_PUSHIMGBTN, 14, 150, 199, 58, 65, 0x0, STR_0330_SELECT_EZY_STREET_STYLE},
{ WWT_PUSHIMGBTN, 14, 200, 249, 58, 65, 0x0, STR_01F6_SELECT_CUSTOM_1_USER_DEFINED},
{ WWT_PUSHIMGBTN, 14, 250, 299, 58, 65, 0x0, STR_01F7_SELECT_CUSTOM_2_USER_DEFINED},
{ WWT_LAST},
};
static const WindowDesc _music_window_desc = {
0, 22, 300, 66,
WC_MUSIC_WINDOW,0,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
_music_window_widgets,
MusicWindowWndProc
};
void ShowMusicWindow()
{
AllocateWindowDescFront(&_music_window_desc, 0);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,426 @@
#include "stdafx.h"
#include "ttd.h"
#include "window.h"
#include "gui.h"
#include "gfx.h"
#include "command.h"
#define BGC 5
#define BTC 15
#define MAX_QUERYSTR_LEN 64
static byte _edit_str_buf[MAX_QUERYSTR_LEN*2];
static void ShowNetworkStartServerWindow();
static void ShowNetworkLobbyWindow();
extern void ShowDropDownMenu(Window *w, const StringID *strings, int selected, int button, uint32 disabled_mask);
extern int HandleEditBoxKey(Window *w, int wid, WindowEvent *we);
void ShowQueryString(StringID str, StringID caption, int maxlen, int maxwidth, byte window_class, uint16 window_number);
static byte _selected_field;
char *direct_ip = NULL;
void ConnectToServer(byte* b)
{
_networking = true;
NetworkInitialize();
DEBUG(misc, 1) ("Connecting to %s %d\n", b, _network_port);
NetworkConnect(b, _network_port);
}
static const StringID _connection_types_dropdown[] = {
STR_NETWORK_LAN,
STR_NETWORK_INTERNET,
INVALID_STRING_ID
};
static void NetworkGameWindowWndProc(Window *w, WindowEvent *e)
{
switch(e->event) {
case WE_PAINT: {
SET_DPARAM16(0, 0x00);
SET_DPARAM16(2, STR_NETWORK_LAN + _opt_mod_ptr->road_side);
DrawWindowWidgets(w);
DrawEditBox(w, 6);
DrawString(9, 43, STR_NETWORK_PLAYER_NAME, 2);
DrawString(9, 63, STR_NETWORK_SELECT_CONNECTION, 2);
DrawString(15, 82, STR_NETWORK_GAME_NAME, 2);
DrawString(238, 82, STR_NETWORK_PLAYERS, 2);
DrawString(288, 82, STR_NETWORK_MAP_SIZE, 2);
break;
}
case WE_CLICK:
_selected_field = e->click.widget;
switch(e->click.widget) {
case 0: // close X
case 15: // cancel button
DeleteWindowById(WC_NETWORK_WINDOW, 0);
break;
case 4: // connect via direct ip
{
StringID str;
str = AllocateName((byte*)_decode_parameters, 0);
ShowQueryString(
str,
STR_NETWORK_ENTER_IP,
15,
160,
w->window_class,
w->window_number);
DeleteName(str);
}
break;
case 5: // start server
ShowNetworkStartServerWindow();
break;
case 8:
ShowDropDownMenu(w, _connection_types_dropdown, _opt_mod_ptr->currency, e->click.widget, 0);
return;
}
case WE_MOUSELOOP:
if(_selected_field != 6)
break;
HandleEditBox(w, 6);
break;
case WE_KEYPRESS:
if(_selected_field != 6)
break;
switch (HandleEditBoxKey(w, 6, e)) {
case 1:
HandleButtonClick(w, 9);
break;
}
break;
case WE_ON_EDIT_TEXT: {
byte *b = e->edittext.str;
if (*b == 0)
return;
ConnectToServer(b);
} break;
}
}
static const Widget _network_game_window_widgets[] = {
{ WWT_PUSHTXTBTN, BGC, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, BGC, 10, 399, 0, 13, STR_NETWORK_MULTIPLAYER},
{ WWT_IMGBTN, BGC, 0, 399, 14, 199, 0x0},
{ WWT_PUSHTXTBTN, BTC, 20, 130, 22, 33, STR_NETWORK_FIND_SERVER, STR_NETWORK_FIND_SERVER_TIP},
{ WWT_PUSHTXTBTN, BTC, 145, 255, 22, 33, STR_NETWORK_DIRECT_CONNECT, STR_NETWORK_DIRECT_CONNECT_TIP},
{ WWT_PUSHTXTBTN, BTC, 270, 380, 22, 33, STR_NETWORK_START_SERVER, STR_NETWORK_START_SERVER_TIP},
{ WWT_IMGBTN, BGC, 250, 394, 42, 53, 0x0, STR_NETWORK_ENTER_NAME_TIP},
{ WWT_6, BGC, 250, 393, 62, 73, STR_NETWORK_COMBO1, STR_NETWORK_CONNECTION_TYPE_TIP},
{ WWT_CLOSEBOX, BGC, 382, 392, 63, 72, STR_0225, STR_NETWORK_CONNECTION_TYPE_TIP},
{ WWT_SCROLLBAR, BGC, 382, 392, 81, 175, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
{ WWT_IMGBTN, BTC, 10, 231, 81, 92, 0x0, STR_NETWORK_GAME_NAME_TIP },
{ WWT_IMGBTN, BTC, 232, 281, 81, 92, 0x0, STR_NETWORK_PLAYERS_TIP },
{ WWT_IMGBTN, BTC, 282, 331, 81, 92, 0x0, STR_NETWORK_MAP_SIZE_TIP },
{ WWT_IMGBTN, BTC, 332, 381, 81, 92, 0x0, STR_NETWORK_INFO_ICONS_TIP },
{ WWT_MATRIX, BGC, 10, 381, 93, 175, 0x601, STR_NETWORK_CLICK_GAME_TO_SELECT},
{ WWT_PUSHTXTBTN, BTC, 145, 255, 180, 191, STR_012E_CANCEL, STR_NULL},
{ WWT_PUSHTXTBTN, BTC, 270, 392, 180, 191, STR_NETWORK_JOIN_GAME, STR_NULL},
{ WWT_LAST},
};
static const WindowDesc _network_game_window_desc = {
WDP_CENTER, WDP_CENTER, 400, 200,
WC_NETWORK_WINDOW,0,
WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
_network_game_window_widgets,
NetworkGameWindowWndProc,
};
void ShowNetworkGameWindow()
{
Window *w;
DeleteWindowById(WC_NETWORK_WINDOW, 0);
w = AllocateWindowDesc(&_network_game_window_desc);
strcpy(_edit_str_buf, "Your name");
WP(w,querystr_d).caret = 1;
WP(w,querystr_d).maxlen = MAX_QUERYSTR_LEN;
WP(w,querystr_d).maxwidth = 240;
WP(w,querystr_d).buf = _edit_str_buf;
ShowErrorMessage(-1, TEMP_STRING_NO_NETWORK, 0, 0);
}
void StartServer()
{
_networking = true;
NetworkInitialize();
DEBUG(misc, 1) ("Listening on port %d\n", _network_port);
NetworkListen(_network_port);
_networking_server = true;
DoCommandP(0, 0, 0, NULL, CMD_START_NEW_GAME);
}
static const StringID _players_dropdown[] = {
STR_NETWORK_2_PLAYERS,
STR_NETWORK_3_PLAYERS,
STR_NETWORK_4_PLAYERS,
STR_NETWORK_5_PLAYERS,
STR_NETWORK_6_PLAYERS,
STR_NETWORK_7_PLAYERS,
STR_NETWORK_8_PLAYERS,
INVALID_STRING_ID
};
static void NetworkStartServerWindowWndProc(Window *w, WindowEvent *e)
{
switch(e->event) {
case WE_PAINT: {
SET_DPARAM16(7, STR_NETWORK_2_PLAYERS + _opt_mod_ptr->road_side);
DrawWindowWidgets(w);
GfxFillRect(11, 63, 237, 168, 0xD7);
DrawEditBox(w, 3);
DrawEditBox(w, 4);
DrawString(10, 22, STR_NETWORK_NEW_GAME_NAME, 2);
DrawString(210, 22, STR_NETWORK_PASSWORD, 2);
DrawString(10, 43, STR_NETWORK_SELECT_MAP, 2);
DrawString(260, 63, STR_NETWORK_NUMBER_OF_PLAYERS, 2);
break;
}
case WE_CLICK:
_selected_field = e->click.widget;
switch(e->click.widget) {
case 0: // close X
case 10: // cancel button
ShowNetworkGameWindow();
break;
case 8:
ShowDropDownMenu(w, _players_dropdown, _opt_mod_ptr->currency, e->click.widget, 0);
return;
case 9: // start game
StartServer();
ShowNetworkLobbyWindow();
break;
}
case WE_MOUSELOOP:
if(_selected_field == 3)
{
HandleEditBox(w, 3);
break;
}
if(_selected_field == 4)
{
HandleEditBox(w, 4);
break;
}
break;
case WE_KEYPRESS:
if(_selected_field != 3 && _selected_field != 4)
break;
switch (HandleEditBoxKey(w, _selected_field, e)) {
case 1:
HandleButtonClick(w, 9);
break;
}
break;
}
}
static const Widget _network_start_server_window_widgets[] = {
{ WWT_PUSHTXTBTN, BGC, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW },
{ WWT_CAPTION, BGC, 10, 399, 0, 13, STR_NETWORK_START_GAME_WINDOW },
{ WWT_IMGBTN, BGC, 0, 399, 14, 199, 0x0},
{ WWT_IMGBTN, BGC, 80, 190, 22, 33, 0x0, STR_NETWORK_NEW_GAME_NAME_TIP},
{ WWT_IMGBTN, BGC, 280, 390, 22, 33, 0x0, STR_NETWORK_PASSWORD_TIP},
{ WWT_IMGBTN, BGC, 10, 240, 62, 170, 0x0, STR_NETWORK_SELECT_MAP_TIP},
{ WWT_SCROLLBAR, BGC, 241, 251, 62, 170, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
{ WWT_6, BGC, 260, 390, 81, 92, STR_NETWORK_COMBO2, STR_NETWORK_NUMBER_OF_PLAYERS_TIP},
{ WWT_CLOSEBOX, BGC, 378, 388, 82, 91, STR_0225, STR_NETWORK_NUMBER_OF_PLAYERS_TIP},
{ WWT_PUSHTXTBTN, BTC, 80, 180, 180, 191, STR_NETWORK_START_GAME, STR_NULL},
{ WWT_PUSHTXTBTN, BTC, 220, 320, 180, 191, STR_012E_CANCEL, STR_NULL},
{ WWT_LAST},
};
static const WindowDesc _network_start_server_window_desc = {
WDP_CENTER, WDP_CENTER, 400, 200,
WC_NETWORK_WINDOW,0,
WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
_network_start_server_window_widgets,
NetworkStartServerWindowWndProc,
};
static void ShowNetworkStartServerWindow()
{
Window *w;
DeleteWindowById(WC_NETWORK_WINDOW, 0);
w = AllocateWindowDesc(&_network_start_server_window_desc);
strcpy(_edit_str_buf, "");
WP(w,querystr_d).caret = 1;
WP(w,querystr_d).maxlen = MAX_QUERYSTR_LEN;
WP(w,querystr_d).maxwidth = 240;
WP(w,querystr_d).buf = _edit_str_buf;
}
static void NetworkLobbyWindowWndProc(Window *w, WindowEvent *e)
{
switch(e->event) {
case WE_PAINT: {
SET_DPARAM16(7, STR_NETWORK_2_PLAYERS + _opt_mod_ptr->road_side);
DrawWindowWidgets(w);
GfxFillRect( 11, 31, 239, 239, 0xD7);
GfxFillRect(261, 31, 378, 220, 0xD7);
DrawEditBox(w, 5);
DrawEditBox(w, 7);
DrawString(10, 255, STR_NETWORK_COMPANY_NAME, 2);
break;
}
case WE_CLICK:
_selected_field = e->click.widget;
switch(e->click.widget) {
case 0: // close X
case 13: // cancel button
ShowNetworkGameWindow();
break;
}
case WE_MOUSELOOP:
if(_selected_field == 5)
{
HandleEditBox(w, 5);
break;
}
if(_selected_field == 7)
{
HandleEditBox(w, 7);
break;
}
break;
case WE_KEYPRESS:
if(_selected_field != 5 && _selected_field != 7)
break;
switch (HandleEditBoxKey(w, _selected_field, e)) {
case 1:
HandleButtonClick(w, 12);
break;
}
break;
}
}
static const Widget _network_lobby_window_widgets[] = {
{ WWT_PUSHTXTBTN, BGC, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW },
{ WWT_CAPTION, BGC, 10, 399, 0, 13, STR_NETWORK_GAME_LOBBY },
{ WWT_IMGBTN, BGC, 0, 399, 14, 299, 0x0},
// chat widget
{ WWT_IMGBTN, BGC, 10, 240, 30, 240, 0x0},
{ WWT_SCROLLBAR, BGC, 241, 251, 30, 240, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
// send message prompt
{ WWT_IMGBTN, BGC, 10, 200, 241, 252, 0x0, STR_NETWORK_ENTER_NAME_TIP},
{ WWT_PUSHTXTBTN, BTC, 201, 251, 241, 252, STR_NETWORK_SEND, STR_NETWORK_SEND_TIP},
// company name
{ WWT_IMGBTN, BGC, 100, 251, 254, 265, 0x0, STR_NETWORK_COMPANY_NAME_TIP},
// player information
{ WWT_IMGBTN, BGC, 260, 379, 30, 221, 0x0},
{ WWT_SCROLLBAR, BGC, 380, 390, 30, 221, 0x1, STR_0190_SCROLL_BAR_SCROLLS_LIST},
// buttons
{ WWT_PUSHTXTBTN, BTC, 260, 390, 233, 244, STR_NETWORK_NEW_COMPANY, STR_NETWORK_NEW_COMPANY_TIP},
{ WWT_PUSHTXTBTN, BTC, 260, 390, 254, 265, STR_NETWORK_SPECTATE_GAME, STR_NETWORK_SPECTATE_GAME_TIP},
{ WWT_PUSHTXTBTN, BTC, 80, 180, 280, 291, STR_NETWORK_READY, STR_NULL},
{ WWT_PUSHTXTBTN, BTC, 220, 320, 280, 291, STR_012E_CANCEL, STR_NULL},
{ WWT_LAST},
};
static const WindowDesc _network_lobby_window_desc = {
WDP_CENTER, WDP_CENTER, 400, 300,
WC_NETWORK_WINDOW,0,
WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
_network_lobby_window_widgets,
NetworkLobbyWindowWndProc,
};
static void ShowNetworkLobbyWindow()
{
Window *w;
DeleteWindowById(WC_NETWORK_WINDOW, 0);
w = AllocateWindowDesc(&_network_lobby_window_desc);
strcpy(_edit_str_buf, "");
WP(w,querystr_d).caret = 1;
WP(w,querystr_d).maxlen = MAX_QUERYSTR_LEN;
WP(w,querystr_d).maxwidth = 240;
WP(w,querystr_d).buf = _edit_str_buf;
}

@ -0,0 +1,68 @@
#ifndef NEWS_H
#define NEWS_H
struct NewsItem {
StringID string_id;
uint16 duration;
uint16 date;
byte flags;
byte display_mode;
byte type;
byte callback;
TileIndex data_a;
TileIndex data_b;
uint32 params[10];
};
#define NEWS_FLAGS(mode,flag,type,cb) ((cb)<<24 | (type)<<16 | (flag)<<8 | (mode))
void AddNewsItem(StringID string, uint32 flags, uint data_a, uint data_b);
void NewsLoop();
void DrawNewsBorder(Window *w);
void InitNewsItemStructs();
VARDEF NewsItem _statusbar_news_item;
typedef void DrawNewsCallbackProc(Window *w);
typedef StringID GetNewsStringCallbackProc(NewsItem *ni);
enum {
NT_ARRIVAL_PLAYER = 0,
NT_ARRIVAL_OTHER = 1,
NT_ACCIDENT = 2,
NT_COMPANY_INFO = 3,
NT_ECONOMY = 4,
NT_ADVICE = 5,
NT_NEW_VEHICLES = 6,
NT_ACCEPTANCE = 7,
NT_SUBSIDIES = 8,
NT_GENERAL = 9,
};
enum NewsMode {
NM_SMALL = 0,
NM_NORMAL = 1,
NM_THIN = 2,
NM_CALLBACK = 3,
};
enum NewsFlags {
NF_VIEWPORT = 1,
NF_TILE = 4,
NF_VEHICLE = 8,
NF_FORCE_BIG = 0x10,
NF_NOEXPIRE = 0x20,
NF_INCOLOR = 0x40,
};
enum {
DNC_TRAINAVAIL = 0,
DNC_ROADAVAIL = 1,
DNC_SHIPAVAIL = 2,
DNC_AIRCRAFTAVAIL = 3,
DNC_BANKRUPCY = 4,
};
#endif /* NEWS_H */

@ -0,0 +1,615 @@
#include "stdafx.h"
#include "ttd.h"
#include "window.h"
#include "gui.h"
#include "viewport.h"
#include "gfx.h"
#include "news.h"
#include "vehicle.h"
static NewsItem _news_items[10];
static NewsItem _active_news_items[20];
void ExpireNewsItem();
void DrawNewsNewTrainAvail(Window *w);
void DrawNewsNewRoadVehAvail(Window *w);
void DrawNewsNewShipAvail(Window *w);
void DrawNewsNewAircraftAvail(Window *w);
void DrawNewsBankrupcy(Window *w);
StringID GetNewsStringNewTrainAvail(NewsItem *ni);
StringID GetNewsStringNewRoadVehAvail(NewsItem *ni);
StringID GetNewsStringNewShipAvail(NewsItem *ni);
StringID GetNewsStringNewAircraftAvail(NewsItem *ni);
StringID GetNewsStringBankrupcy(NewsItem *ni);
static DrawNewsCallbackProc * const _draw_news_callback[] = {
DrawNewsNewTrainAvail, /* DNC_TRAINAVAIL */
DrawNewsNewRoadVehAvail, /* DNC_ROADAVAIL */
DrawNewsNewShipAvail, /* DNC_SHIPAVAIL */
DrawNewsNewAircraftAvail, /* DNC_AIRCRAFTAVAIL */
DrawNewsBankrupcy, /* DNC_BANKRUPCY */
};
GetNewsStringCallbackProc * const _get_news_string_callback[] = {
GetNewsStringNewTrainAvail, /* DNC_TRAINAVAIL */
GetNewsStringNewRoadVehAvail, /* DNC_ROADAVAIL */
GetNewsStringNewShipAvail, /* DNC_SHIPAVAIL */
GetNewsStringNewAircraftAvail, /* DNC_AIRCRAFTAVAIL */
GetNewsStringBankrupcy, /* DNC_BANKRUPCY */
};
void DrawNewsBorder(Window *w)
{
int left = 0;
int right = w->width - 1;
int top = 0;
int bottom = w->height - 1;
GfxFillRect(left, top, right, bottom, 0xF);
GfxFillRect(left, top, left, bottom, 0xD7);
GfxFillRect(right, top, right, bottom, 0xD7);
GfxFillRect(left, top, right, top, 0xD7);
GfxFillRect(left, bottom, right, bottom, 0xD7);
DrawString(left + 2, top + 1, STR_00C6, 0);
}
static void NewsWindowProc(Window *w, WindowEvent *e)
{
switch(e->event) {
case WE_PAINT: {
NewsItem *ni = WP(w,news_d).ni;
ViewPort *vp;
if (ni->display_mode == NM_NORMAL || ni->display_mode == NM_THIN) {
DrawNewsBorder(w);
DrawString(2, 1, STR_00C6, 0);
SET_DPARAM16(0, ni->date);
DrawStringRightAligned(428, 1, STR_01FF, 0);
if (!(ni->flags & NF_VIEWPORT)) {
COPY_IN_DPARAM(0, ni->params, lengthof(ni->params));
DrawStringMultiCenter(215, ni->display_mode == NM_NORMAL ? 76 : 56, ni->string_id, 426);
} else {
byte bk = _display_opt;
_display_opt |= DO_TRANS_BUILDINGS;
DrawWindowViewport(w);
_display_opt = bk;
/* Shade the viewport into gray, or color*/
vp = w->viewport;
GfxFillRect(vp->left - w->left, vp->top - w->top, vp->left - w->left + vp->width - 1, vp->top - w->top + vp->height - 1,
ni->flags & NF_INCOLOR ? 0x4322:0x4323
);
COPY_IN_DPARAM(0, ni->params, lengthof(ni->params));
DrawStringMultiCenter((w->width>>1), 20, ni->string_id, 428);
}
} else if (ni->display_mode == NM_CALLBACK) {
_draw_news_callback[ni->callback](w);
} else {
DrawWindowWidgets(w);
if (!(ni->flags & NF_VIEWPORT)) {
COPY_IN_DPARAM(0, ni->params, lengthof(ni->params));
DrawStringMultiCenter(140,38, ni->string_id, 276);
} else {
DrawWindowViewport(w);
COPY_IN_DPARAM(0, ni->params, lengthof(ni->params));
DrawStringMultiCenter((w->width>>1), w->height - 16, ni->string_id, 276);
}
}
} break;
case WE_CLICK: {
switch(e->click.widget) {
case 1:DeleteWindow(w); ExpireNewsItem(); break;
case 0: {
NewsItem *ni = WP(w,news_d).ni;
if (ni->flags & NF_VEHICLE) {
Vehicle *v = &_vehicles[ni->data_a];
ScrollMainWindowTo(v->x_pos, v->y_pos);
} else if (ni->flags & NF_TILE) {
if (!ScrollMainWindowToTile(ni->data_a) && ni->data_b != 0)
ScrollMainWindowToTile(ni->data_b);
}
} break;
}
} break;
case WE_KEYPRESS:
if (e->keypress.keycode == WKC_SPACE) {
// Don't continue.
e->keypress.cont = false;
DeleteWindow(w);
ExpireNewsItem();
}
break;
case WE_TICK: {
int y = max(w->top - 4, _screen.height - w->height);
if (y == w->top)
return;
if (w->viewport != NULL)
w->viewport->top += y - w->top;
w->top = y;
SetDirtyBlocks(w->left, w->top, w->left + w->width, w->top + w->height + 4);
} break;
}
}
void AddNewsItem(StringID string, uint32 flags, uint data_a, uint data_b)
{
NewsItem *ni;
if (_game_mode == GM_MENU)
return;
// Find a free place and add it there.
for(ni=_news_items; ni!=endof(_news_items); ni++) {
if (ni->string_id==0) {
ni->string_id = string;
ni->display_mode = (byte)flags;
ni->flags = (byte)(flags >> 8) | NF_NOEXPIRE;
// show this news message in color?
if (_date >= ConvertIntDate(_patches.colored_news_date))
ni->flags |= NF_INCOLOR;
ni->type = (byte)(flags >> 16);
ni->callback = (byte)(flags >> 24);
ni->duration = 555;
ni->data_a = data_a;
ni->data_b = data_b;
ni->date = _date;
COPY_OUT_DPARAM(ni->params, 0, lengthof(ni->params));
break;
}
}
}
// _active_news_items 0..9 are the ones that have already been shown
// _active_news_items 10..19 are the ones that are to be shown next
static void MoveNewsItems()
{
Window *w;
NewsItem *ni;
// No new news item?
if (_news_items[0].string_id == 0)
return;
// Check if the status bar message is still being displayed?
w = FindWindowById(WC_STATUS_BAR, 0);
if (w != NULL && WP(w,def_d).data_1 > -1280)
return;
// Add the news items to the list of pending ones.
for(ni=_active_news_items + 10; ni != _active_news_items + 20; ni++) {
if (ni->string_id == 0) {
*ni = _news_items[0];
memcpy_overlapping(_news_items, _news_items+1, sizeof(_news_items) - sizeof(_news_items[0]) * 1);
endof(_news_items)[-1].string_id = 0;
break;
}
}
}
void ExpireNewsItem()
{
memcpy_overlapping(_active_news_items, _active_news_items + 1, sizeof(_active_news_items) - sizeof(_active_news_items[0]));
endof(_active_news_items)[-1].string_id = 0;
}
static const byte _news_items_age[] = {60, 60, 90, 60, 90, 30, 150, 30, 90, 180};
static void RemoveOldNewsItems()
{
NewsItem *ni, *nit;
ni = _active_news_items;
do {
if (ni->string_id != 0 &&
ni != _active_news_items + 10 &&
_date - _news_items_age[ni->type] > ni->date) {
if (ni >= _active_news_items + 10) {
nit = ni;
while (nit != _active_news_items + 19) {
nit[0] = nit[1];
nit++;
}
nit->string_id = 0;
} else {
nit = ni + 1;
while (nit != _active_news_items + 1) {
nit--;
nit[0] = nit[-1];
}
_active_news_items[0].string_id = 0;
}
}
} while (++ni != endof(_active_news_items) );
}
static const Widget _news_type13_widgets[] = {
{ WWT_PANEL, 15, 0, 429, 0, 169, 0x0},
{ WWT_PANEL, 15, 0, 10, 0, 11, 0x0},
{ WWT_LAST},
};
static WindowDesc _news_type13_desc = {
WDP_CENTER, 476, 430, 170,
WC_NEWS_WINDOW,0,
WDF_DEF_WIDGET,
_news_type13_widgets,
NewsWindowProc
};
static const Widget _news_type2_widgets[] = {
{ WWT_PANEL, 15, 0, 429, 0, 129, 0x0},
{ WWT_PANEL, 15, 0, 10, 0, 11, 0x0},
{ WWT_LAST},
};
static WindowDesc _news_type2_desc = {
WDP_CENTER, 476, 430, 130,
WC_NEWS_WINDOW,0,
WDF_DEF_WIDGET,
_news_type2_widgets,
NewsWindowProc
};
static const Widget _news_type0_widgets[] = {
{ WWT_PANEL, 5, 0, 279, 14, 86, 0x0},
{ WWT_CLOSEBOX, 5, 0, 10, 0, 13, STR_00C5},
{ WWT_CAPTION, 5, 11, 279, 0, 13, STR_012C_MESSAGE},
{ WWT_6, 5, 2, 277, 16, 64, 0},
{ WWT_LAST},
};
static WindowDesc _news_type0_desc = {
WDP_CENTER, 476, 280, 87,
WC_NEWS_WINDOW,0,
WDF_DEF_WIDGET,
_news_type0_widgets,
NewsWindowProc
};
static byte _news_sounds[] = { 27, 27, 0, 0, 0, 0, 28, 0, 0, 0 };
static void ProcessNewsItem(NewsItem *ni)
{
Window *w;
int sound;
// No news item, quit
if (ni->string_id == 0)
return;
// Delete the item once the duration reaches 0
if (ni->duration == 0) {
DeleteWindowById(WC_NEWS_WINDOW, 0);
ExpireNewsItem();
return;
}
ni->duration--;
// As long as the window still is shown, don't go further
w = FindWindowById(WC_NEWS_WINDOW, 0);
if (w != NULL)
return;
// Expire the item if NF_NOEXPIRE was removed
if (!(ni->flags & NF_NOEXPIRE)) {
ExpireNewsItem();
return;
}
if (!HASBIT(_news_display_opt, ni->type) && !(ni->flags&NF_FORCE_BIG)) {
SndPlayFx(20);
_statusbar_news_item = *ni;
w = FindWindowById(WC_STATUS_BAR, 0);
if (w != 0)
WP(w,def_d).data_1 = 360;
ExpireNewsItem();
} else {
int top;
ni->flags &= ~(NF_NOEXPIRE|NF_FORCE_BIG);
sound = _news_sounds[ni->type];
if (sound != 0)
SndPlayFx(sound);
top = _screen.height - 4;
if (ni->display_mode == NM_NORMAL || ni->display_mode == NM_CALLBACK) {
_news_type13_desc.top = top;
w = AllocateWindowDesc(&_news_type13_desc);
if (ni->flags & NF_VIEWPORT) {
AssignWindowViewport(w, 2, 58, 0x1AA, 0x6E, ni->data_a | ((ni->flags&NF_VEHICLE) ? 0x80000000 : 0), 0);
}
} else if (ni->display_mode == NM_THIN) {
_news_type2_desc.top = top;
w = AllocateWindowDesc(&_news_type2_desc);
if (ni->flags & NF_VIEWPORT) {
AssignWindowViewport(w, 2, 58, 0x1AA, 0x46, ni->data_a | ((ni->flags&NF_VEHICLE) ? 0x80000000 : 0), 0);
}
} else {
_news_type0_desc.top = top;
w = AllocateWindowDesc(&_news_type0_desc);
if (ni->flags & NF_VIEWPORT) {
AssignWindowViewport(w, 3, 17, 0x112, 0x2F, ni->data_a | ((ni->flags&NF_VEHICLE) ? 0x80000000 : 0), 0);
}
}
WP(w,news_d).ni = _active_news_items + 10;
w->flags4 |= WF_DISABLE_VP_SCROLL;
}
}
void NewsLoop()
{
RemoveOldNewsItems();
MoveNewsItems();
ProcessNewsItem(_active_news_items + 10);
}
void ShowLastNewsMessage()
{
// No news item immediately before 10?
if (_active_news_items[9].string_id == 0)
return;
// Delete the news window
DeleteWindowById(WC_NEWS_WINDOW, 0);
// Move all items one step
memmove(_active_news_items+1, _active_news_items, sizeof(NewsItem)*19);
_active_news_items[0].string_id = 0;
// Default duration and flags for re-shown items
_active_news_items[10].duration = 555;
_active_news_items[10].flags |= NF_NOEXPIRE | NF_FORCE_BIG;
}
void InitNewsItemStructs()
{
memset(_news_items, 0, sizeof(_news_items));
memset(_active_news_items, 0, sizeof(_active_news_items));
}
static void MessageOptionsWndProc(Window *w, WindowEvent *e)
{
switch(e->event) {
case WE_PAINT: {
uint16 x = _news_display_opt;
uint32 cs = 0;
int i, y;
for(i=3; i!=23; i+=2) {
cs |= 1 << (i + (x&1));
x >>= 1;
}
cs |= (w->click_state >> 23) << 23;
w->click_state = cs;
DrawWindowWidgets(w);
DrawStringCentered(185, 15, STR_0205_MESSAGE_TYPES, 0);
y = 27;
for(i=STR_0206_ARRIVAL_OF_FIRST_VEHICLE; i <= STR_020F_GENERAL_INFORMATION; i++) {
DrawString(124, y, i, 0);
y += 12;
}
break;
}
case WE_CLICK: {
int wid;
if ( (uint)(wid=e->click.widget - 3) < 20) {
if (!(wid & 1)) {
_news_display_opt &= ~(1 << (wid>>1));
} else {
_news_display_opt |= (1 << (wid>>1));
}
SetWindowDirty(w);
/* XXX: write settings */
}
if( e->click.widget == 23) {
_news_display_opt = 0;
HandleButtonClick(w, 23);
SetWindowDirty(w);
}
if( e->click.widget == 24) {
_news_display_opt = ~0;
HandleButtonClick(w, 24);
SetWindowDirty(w);
}
} break;
}
}
static const Widget _message_options_widgets[] = {
{ WWT_CLOSEBOX, 13, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, 13, 11, 369, 0, 13, STR_0204_MESSAGE_OPTIONS, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PANEL, 13, 0, 369, 14, 172, 0x0},
{ WWT_CLOSEBOX, 3, 2, 61, 26, 37, STR_02B8_SUMMARY},
{ WWT_CLOSEBOX, 3, 62, 121, 26, 37, STR_02B9_FULL},
{ WWT_CLOSEBOX, 3, 2, 61, 38, 49, STR_02B8_SUMMARY},
{ WWT_CLOSEBOX, 3, 62, 121, 38, 49, STR_02B9_FULL},
{ WWT_CLOSEBOX, 3, 2, 61, 50, 61, STR_02B8_SUMMARY},
{ WWT_CLOSEBOX, 3, 62, 121, 50, 61, STR_02B9_FULL},
{ WWT_CLOSEBOX, 3, 2, 61, 62, 73, STR_02B8_SUMMARY},
{ WWT_CLOSEBOX, 3, 62, 121, 62, 73, STR_02B9_FULL},
{ WWT_CLOSEBOX, 3, 2, 61, 74, 85, STR_02B8_SUMMARY},
{ WWT_CLOSEBOX, 3, 62, 121, 74, 85, STR_02B9_FULL},
{ WWT_CLOSEBOX, 3, 2, 61, 86, 97, STR_02B8_SUMMARY},
{ WWT_CLOSEBOX, 3, 62, 121, 86, 97, STR_02B9_FULL},
{ WWT_CLOSEBOX, 3, 2, 61, 98, 109, STR_02B8_SUMMARY},
{ WWT_CLOSEBOX, 3, 62, 121, 98, 109, STR_02B9_FULL},
{ WWT_CLOSEBOX, 3, 2, 61, 110, 121, STR_02B8_SUMMARY},
{ WWT_CLOSEBOX, 3, 62, 121, 110, 121, STR_02B9_FULL},
{ WWT_CLOSEBOX, 3, 2, 61, 122, 133, STR_02B8_SUMMARY},
{ WWT_CLOSEBOX, 3, 62, 121, 122, 133, STR_02B9_FULL},
{ WWT_CLOSEBOX, 3, 2, 61, 134, 145, STR_02B8_SUMMARY},
{ WWT_CLOSEBOX, 3, 62, 121, 134, 145, STR_02B9_FULL},
{ WWT_PUSHTXTBTN, 3, 15, 170, 154, 165, STR_MESSAGES_DISABLE_ALL, STR_NULL },
{ WWT_PUSHTXTBTN, 3, 200, 355, 154, 165, STR_MESSAGES_ENABLE_ALL, STR_NULL },
{ WWT_LAST},
};
static const WindowDesc _message_options_desc = {
270, 22, 370, 173,
WC_GAME_OPTIONS,0,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
_message_options_widgets,
MessageOptionsWndProc
};
void ShowMessageOptions()
{
DeleteWindowById(WC_GAME_OPTIONS, 0);
AllocateWindowDesc(&_message_options_desc);
}
static void GetNewsString(NewsItem *ni, byte *buffer)
{
StringID str;
byte *s, *d;
if (ni->display_mode == 3) {
str = _get_news_string_callback[ni->callback](ni);
} else {
COPY_IN_DPARAM(0, ni->params, lengthof(ni->params));
str = ni->string_id;
}
GetString(str_buffr, str);
assert(strlen(str_buffr) < sizeof(str_buffr) - 1);
s = str_buffr;
d = buffer;
for(;;s++) {
// cut strings that are too long
if(s >= str_buffr + 55) {
d[0] = d[1] = d[2] = '.';
d+=3;
*d = 0;
break;
}
if (*s == 0) {
*d = 0;
break;
} else if (*s == 13) {
d[0] = d[1] = d[2] = d[3] = ' ';
d+=4;
} else if (*s >= ' ' && (*s < 0x88 || *s >= 0x99)) {
*d++ = *s;
}
}
}
static void MessageHistoryWndProc(Window *w, WindowEvent *e)
{
switch(e->event) {
case WE_PAINT: {
uint n, y, i;
char buffer[256];
NewsItem *ni;
for(n=10; n!=0; n--)
if (!_active_news_items[n - 1].string_id)
break;
n = 10 - n;
SetVScrollCount(w, n);
DrawWindowWidgets(w);
y = 18;
for(i=w->vscroll.pos; i!=n; i++) {
ni = &_active_news_items[i + (10 - n)];
assert(ni->string_id);
SET_DPARAM16(0, ni->date);
DrawString(4, y, STR_00AF, 16);
GetNewsString(ni, buffer);
DoDrawString(buffer, 85, y, 16);
y += 12;
}
break;
}
case WE_CLICK:
switch(e->click.widget) {
case 2: {
uint y = (e->click.pt.y - 18) / 12;
NewsItem *ni;
if (y >= (uint)w->vscroll.count)
return;
ni = &_active_news_items[w->vscroll.pos + y + (10 - w->vscroll.count)];
// NOT YET...
// ShowNewsMessage(y);
break;
}
}
break;
}
}
static const Widget _message_history_widgets[] = {
{ WWT_CLOSEBOX, 13, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, 13, 11, 399, 0, 13, STR_MESSAGE_HISTORY, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_IMGBTN, 13, 0, 388, 14, 147, 0x0, STR_MESSAGE_HISTORY_TIP},
{ WWT_SCROLLBAR, 13, 389, 399, 14, 147, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
{ WWT_LAST},
};
static const WindowDesc _message_history_desc = {
240, 22, 400, 148,
WC_MESSAGE_HISTORY,0,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
_message_history_widgets,
MessageHistoryWndProc
};
void ShowMessageHistory()
{
Window *w;
DeleteWindowById(WC_MESSAGE_HISTORY, 0);
w = AllocateWindowDesc(&_message_history_desc);
if (w) {
w->vscroll.cap = 11;
SetWindowDirty(w);
}
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,332 @@
#include "stdafx.h"
#include "ttd.h"
#include "vehicle.h"
#include "command.h"
#include "station.h"
#include "player.h"
/* p1 & 0xFFFF = vehicle
* p1 >> 16 = index in order list
* p2 = order command to insert
*/
int32 CmdInsertOrder(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
Vehicle *v = &_vehicles[p1 & 0xFFFF];
int sel = p1 >> 16;
int t;
if (sel > v->num_orders) return_cmd_error(STR_EMPTY);
if (_ptr_to_next_order == endof(_order_array)) return_cmd_error(STR_8831_NO_MORE_SPACE_FOR_ORDERS);
if (v->num_orders >= 40) return_cmd_error(STR_8832_TOO_MANY_ORDERS);
// for ships, make sure that the station is not too far away from the previous destination.
if (v->type == VEH_Ship && IS_HUMAN_PLAYER(v->owner) &&
sel != 0 && ((t=v->schedule_ptr[sel-1])&OT_MASK) == OT_GOTO_STATION) {
int dist = GetTileDist(DEREF_STATION(t >> 8)->xy, DEREF_STATION(p2 >> 8)->xy);
if (dist >= 130)
return_cmd_error(STR_0210_TOO_FAR_FROM_PREVIOUS_DESTINATIO);
}
if (flags & DC_EXEC) {
uint16 *s1, *s2;
Vehicle *u;
s1 = &v->schedule_ptr[sel];
s2 = _ptr_to_next_order++;
do s2[1] = s2[0]; while (--s2 >= s1);
s1[0] = (uint16)p2;
s1 = v->schedule_ptr;
FOR_ALL_VEHICLES(u) {
if (u->type != 0 && u->schedule_ptr != NULL) {
if (s1 < u->schedule_ptr) {
u->schedule_ptr++;
} else if (s1 == u->schedule_ptr) { // handle shared orders
u->num_orders++;
if ((byte)sel <= u->cur_order_index) {
sel++;
if ((byte)sel < u->num_orders)
u->cur_order_index = sel;
}
InvalidateWindow(WC_VEHICLE_VIEW, u->index);
InvalidateWindow(WC_VEHICLE_ORDERS, u->index);
}
}
}
}
return 0;
}
static int32 DecloneOrder(Vehicle *dst, uint32 flags)
{
if (_ptr_to_next_order == endof(_order_array))
return_cmd_error(STR_8831_NO_MORE_SPACE_FOR_ORDERS);
if (flags & DC_EXEC) {
DeleteVehicleSchedule(dst);
dst->num_orders = 0;
*(dst->schedule_ptr = _ptr_to_next_order++) = 0;
InvalidateWindow(WC_VEHICLE_ORDERS, dst->index);
}
return 0;
}
/* p1 = vehicle
* p2 = sel
*/
int32 CmdDeleteOrder(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
Vehicle *v = &_vehicles[p1], *u;
uint sel = (uint)p2;
_error_message = STR_EMPTY;
if (sel >= v->num_orders)
return DecloneOrder(v, flags);
if (flags & DC_EXEC) {
uint16 *s1;
s1 = &v->schedule_ptr[sel];
// copy all orders to get rid of the hole
do s1[0] = s1[1]; while (++s1 != _ptr_to_next_order);
_ptr_to_next_order--;
s1 = v->schedule_ptr;
FOR_ALL_VEHICLES(u) {
if (u->type != 0 && u->schedule_ptr != NULL) {
if (s1 < u->schedule_ptr) {
u->schedule_ptr--;
} else if (s1 == u->schedule_ptr) {// handle shared orders
u->num_orders--;
if ((byte)sel < u->cur_order_index)
u->cur_order_index--;
if ((byte)sel == u->cur_order_index && (u->next_order&(OT_MASK|OF_NON_STOP)) == (OT_LOADING|OF_NON_STOP))
u->next_order = OT_LOADING;
InvalidateWindow(WC_VEHICLE_VIEW, u->index);
InvalidateWindow(WC_VEHICLE_ORDERS, u->index);
}
}
}
}
return 0;
}
/* p1 = vehicle */
int32 CmdSkipOrder(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
if (flags & DC_EXEC) {
Vehicle *v = &_vehicles[p1];
{
byte b = v->cur_order_index + 1;
if (b >= v->num_orders) b = 0;
v->cur_order_index = b;
if (v->type == VEH_Train)
v->u.rail.days_since_order_progr = 0;
}
if ((v->next_order&(OT_MASK|OF_NON_STOP)) == (OT_LOADING|OF_NON_STOP))
v->next_order = OT_LOADING;
InvalidateWindow(WC_VEHICLE_ORDERS, v->index);
}
return 0;
}
/* p1 = vehicle
* p2&0xFF = sel
* p2>>8 = mode
*/
int32 CmdModifyOrder(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
Vehicle *v = &_vehicles[p1];
byte sel = (byte)p2;
uint16 *sched;
if (sel >= v->num_orders)
return CMD_ERROR;
sched = &v->schedule_ptr[sel];
if (!((*sched & OT_MASK) == OT_GOTO_STATION ||
((*sched & OT_MASK) == OT_GOTO_DEPOT && (p2>>8) != 1)))
return CMD_ERROR;
if (flags & DC_EXEC) {
switch(p2 >> 8) {
case 0: // full load
*sched ^= OF_FULL_LOAD;
if ((*sched & OT_MASK) != OT_GOTO_DEPOT)
*sched &= ~OF_UNLOAD;
break;
case 1: // unload
*sched ^= OF_UNLOAD;
*sched &= ~OF_FULL_LOAD;
break;
case 2: // non stop
*sched ^= OF_NON_STOP;
break;
}
sched = v->schedule_ptr;
FOR_ALL_VEHICLES(v) {
if (v->schedule_ptr == sched)
InvalidateWindow(WC_VEHICLE_ORDERS, v->index);
}
}
return 0;
}
// Clone an order
// p1 & 0xFFFF is destination vehicle
// p1 >> 16 is source vehicle
// p2 is
// 0 - clone
// 1 - copy
// 2 - unclone
int32 CmdCloneOrder(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
Vehicle *dst = &_vehicles[p1 & 0xFFFF];
if (!(dst->type && dst->owner == _current_player))
return CMD_ERROR;
switch(p2) {
// share vehicle orders?
case 0: {
Vehicle *src = &_vehicles[p1 >> 16];
// sanity checks
if (!(src->owner == _current_player && dst->type == src->type && dst != src))
return CMD_ERROR;
if (flags & DC_EXEC) {
DeleteVehicleSchedule(dst);
dst->schedule_ptr = src->schedule_ptr;
dst->num_orders = src->num_orders;
InvalidateWindow(WC_VEHICLE_ORDERS, src->index);
InvalidateWindow(WC_VEHICLE_ORDERS, dst->index);
}
break;
}
// copy vehicle orders?
case 1: {
Vehicle *src = &_vehicles[p1 >> 16];
int delta;
// sanity checks
if (!(src->owner == _current_player && dst->type == src->type && dst != src))
return CMD_ERROR;
// make sure there's orders available
delta = IsScheduleShared(dst) ? src->num_orders + 1 : src->num_orders - dst->num_orders;
if (delta > endof(_order_array) - _ptr_to_next_order)
return_cmd_error(STR_8831_NO_MORE_SPACE_FOR_ORDERS);
if (flags & DC_EXEC) {
DeleteVehicleSchedule(dst);
dst->schedule_ptr = _ptr_to_next_order;
dst->num_orders = src->num_orders;
_ptr_to_next_order += src->num_orders + 1;
memcpy(dst->schedule_ptr, src->schedule_ptr, (src->num_orders + 1) * sizeof(uint16));
InvalidateWindow(WC_VEHICLE_ORDERS, dst->index);
}
break;
}
// declone vehicle orders?
case 2: return DecloneOrder(dst, flags);
}
return 0;
}
void BackupVehicleOrders(Vehicle *v, BackuppedOrders *bak)
{
Vehicle *u = IsScheduleShared(v);
uint16 *sched, ord, *os;
bak->orderindex = v->cur_order_index;
bak->service_interval = v->service_interval;
if ((v->string_id & 0xF800) != 0x7800) {
bak->name[0] = 0;
} else {
GetName(v->string_id & 0x7FF, bak->name);
}
os = bak->order;
// stored shared orders in this special way?
if (u) {
os[0] = 0xFFFF;
os[1] = u->index;
return;
}
sched = v->schedule_ptr;
do {
ord = *sched++;
*os++ = ord;
} while (ord != 0);
}
void RestoreVehicleOrders(Vehicle *v, BackuppedOrders *bak)
{
uint16 ord, *os;
int ind;
if (bak->name[0]) {
strcpy((char*)_decode_parameters, bak->name);
DoCommandP(0, v->index, 0, NULL, CMD_NAME_VEHICLE);
}
DoCommandP(0, v->index, bak->orderindex|(bak->service_interval<<16) , NULL, CMD_RESTORE_ORDER_INDEX | CMD_ASYNC);
os = bak->order;
if (os[0] == 0xFFFF) {
DoCommandP(0, v->index | os[1]<<16, 0, NULL, CMD_CLONE_ORDER);
return;
}
ind = 0;
while ((ord = *os++) != 0) {
if (!DoCommandP(0, v->index + (ind << 16), ord, NULL, CMD_INSERT_ORDER | CMD_ASYNC))
break;
ind++;
}
}
/* p1 = vehicle
* upper 16 bits p2 = service_interval
* lower 16 bits p2 = cur_order_index
*/
int32 CmdRestoreOrderIndex(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
// nonsense to update the windows, since, train rebought will have its window deleted
if (flags & DC_EXEC) {
Vehicle *v = &_vehicles[p1];
v->service_interval = (uint16)(p2>>16);
v->cur_order_index = (byte)(p2&0xFFFF);
}
return 0;
}

@ -0,0 +1,534 @@
#include "stdafx.h"
#include "ttd.h"
#include "window.h"
#include "gui.h"
#include "gfx.h"
#include "vehicle.h"
#include "station.h"
#include "town.h"
#include "command.h"
#include "viewport.h"
static int OrderGetSel(Window *w)
{
Vehicle *v = &_vehicles[w->window_number];
uint16 *sched = v->schedule_ptr;
int num = WP(w,order_d).sel;
int count = 0;
if (num == 0)
return 0;
while (*sched != 0) {
sched++;
count++;
if (--num == 0)
break;
}
return count;
}
static void DrawOrdersWindow(Window *w)
{
Vehicle *v;
int num, sel;
uint16 *sched, ord;
int y, i;
StringID str;
bool shared_schedule;
v = &_vehicles[w->window_number];
w->disabled_state = (v->owner == _local_player) ? 0 : 0x3F0;
shared_schedule = IsScheduleShared(v) != NULL;
sched = v->schedule_ptr;
num=0;
while (*sched != 0)
sched++,num++;
if ((uint)num + shared_schedule <= (uint)WP(w,order_d).sel)
SETBIT(w->disabled_state, 5); /* delete */
if (num == 0)
SETBIT(w->disabled_state, 4); /* skip */
SetVScrollCount(w, num+1);
sel = OrderGetSel(w);
SET_DPARAM16(2,STR_8827_FULL_LOAD);
switch(v->schedule_ptr[sel] & 0x1F) {
case OT_GOTO_STATION:
break;
case OT_GOTO_DEPOT:
SETBIT(w->disabled_state, 9); /* unload */
SET_DPARAM16(2,STR_SERVICE);
break;
default:
SETBIT(w->disabled_state, 6); /* nonstop */
SETBIT(w->disabled_state, 8); /* full load */
SETBIT(w->disabled_state, 9); /* unload */
}
SET_DPARAM16(0, v->string_id);
SET_DPARAM16(1, v->unitnumber);
DrawWindowWidgets(w);
y = 15;
i = 0;
for(;;) {
str = ((byte)v->cur_order_index == i) ? STR_8805 : STR_8804;
ord = v->schedule_ptr[i];
if ( (uint)(i - w->vscroll.pos) < 6) {
if (ord == 0) {
str = shared_schedule ? STR_END_OF_SHARED_ORDERS : STR_882A_END_OF_ORDERS;
} else {
SET_DPARAM16(1, 6);
if ( (ord & OT_MASK) == OT_GOTO_STATION) {
SET_DPARAM16(1, STR_8806_GO_TO + ((ord >> 5) & 7));
SET_DPARAM16(2, ord >> 8);
} else if ((ord & OT_MASK) == OT_GOTO_DEPOT) {
StringID s = STR_NULL;
if (v->type == VEH_Aircraft) {
s = STR_GO_TO_AIRPORT_HANGAR;
SET_DPARAM16(2, ord>>8);
} else {
SET_DPARAM16(2, _depots[ord >> 8].town_index);
switch (v->type) {
case VEH_Train: s = STR_880E_GO_TO_TRAIN_DEPOT; break;
case VEH_Road: s = STR_9038_GO_TO_ROADVEH_DEPOT; break;
case VEH_Ship: s = STR_GO_TO_SHIP_DEPOT; break;
}
}
if (v->type == VEH_Train)
s += (ord>>6)&2;
SET_DPARAM16(1, s + ((ord>>6)&1) );
} else if ((ord & OT_MASK) == OT_GOTO_CHECKPOINT) {
SET_DPARAM16(2, ord >> 8);
SET_DPARAM16(1, STR_GO_TO_CHECKPOINT);
}
}
{
byte color = (i == WP(w,order_d).sel) ? 0xC : 0x10;
SET_DPARAM(0, i+1);
DrawString(2, y, str, color);
}
y += 10;
}
i++;
if (ord == 0)
break;
}
}
// lookup a vehicle on a tile
typedef struct {
TileIndex tile;
byte owner;
byte type;
} FindVehS;
static void *FindVehicleCallb(Vehicle *v, FindVehS *f)
{
if (v->tile != f->tile || v->owner != f->owner || v->vehstatus & VS_HIDDEN ) return NULL;
return v;
}
Vehicle *GetVehicleOnTile(TileIndex tile, byte owner)
{
FindVehS fs = {tile, owner};
return VehicleFromPos(tile, &fs, (VehicleFromPosProc*)FindVehicleCallb);
}
static uint GetOrderCmdFromTile(Vehicle *v, uint tile)
{
Station *st;
int st_index;
// check depot first
if (_patches.gotodepot) {
switch(GET_TILETYPE(tile)) {
case MP_RAILWAY:
if (v->type == VEH_Train && _map_owner[tile] == _local_player) {
if ((_map5[tile]&0xFC)==0xC0)
return (GetDepotByTile(tile)<<8) | OT_GOTO_DEPOT | OF_UNLOAD;
if ((_map5[tile]&0xFE)==0xC4)
return (GetCheckpointByTile(tile)<<8) | OT_GOTO_CHECKPOINT;
}
break;
case MP_STREET:
if ((_map5[tile] & 0xF0) == 0x20 && v->type == VEH_Road && _map_owner[tile] == _local_player)
return (GetDepotByTile(tile)<<8) | OT_GOTO_DEPOT | OF_UNLOAD;
break;
case MP_STATION:
if (v->type != VEH_Aircraft) break;
if ( IsAircraftHangarTile(tile) && _map_owner[tile] == _local_player)
return (_map2[tile]<<8) | OF_UNLOAD | OT_GOTO_DEPOT | OF_NON_STOP;
break;
case MP_WATER:
if (v->type != VEH_Ship) break;
if ( IsShipDepotTile(tile) && _map_owner[tile] == _local_player) {
switch (_map5[tile]) {
case 0x81: tile--; break;
case 0x83: tile-= TILE_XY(0,1); break;
}
return (GetDepotByTile(tile)<<8) | OT_GOTO_DEPOT | OF_UNLOAD;
}
}
}
if (IS_TILETYPE(tile, MP_STATION)) {
st = DEREF_STATION(st_index = _map2[tile]);
if (st->owner == _current_player || st->owner == OWNER_NONE) {
byte facil;
(facil=FACIL_DOCK, v->type == VEH_Ship) ||
(facil=FACIL_TRAIN, v->type == VEH_Train) ||
(facil=FACIL_AIRPORT, v->type == VEH_Aircraft) ||
(facil=FACIL_BUS_STOP, v->type == VEH_Road && v->cargo_type == CT_PASSENGERS) ||
(facil=FACIL_TRUCK_STOP, 1);
if (st->facilities & facil)
return (st_index << 8) | OT_GOTO_STATION;
}
}
// not found
return (uint)-1;
}
static bool HandleOrderVehClick(Vehicle *v, Vehicle *u, Window *w)
{
if (u->type != v->type)
return false;
if (u->type == VEH_Train && u->subtype != 0) {
u = GetFirstVehicleInChain(u);
if (u->subtype != 0)
return false;
}
// v is vehicle getting orders. Only copy/clone orders if vehicle doesn't have any orders yet
// obviously if you press CTRL on a non-empty orders vehicle you know what you are doing
if (v->num_orders != 0 && _ctrl_pressed == 0) {return false;}
if (DoCommandP(v->tile, v->index | (u->index << 16), _ctrl_pressed ? 0 : 1, NULL,
_ctrl_pressed ? CMD_CLONE_ORDER | CMD_MSG(STR_CANT_SHARE_ORDER_LIST) : CMD_CLONE_ORDER | CMD_MSG(STR_CANT_COPY_ORDER_LIST))) {
WP(w,order_d).sel = -1;
ResetObjectToPlace();
}
return true;
}
static void OrdersPlaceObj(Vehicle *v, uint tile, Window *w)
{
uint cmd;
Vehicle *u;
// check if we're clicking on a vehicle first.. clone orders in that case.
u = CheckMouseOverVehicle();
if (u && HandleOrderVehClick(v, u, w))
return;
cmd = GetOrderCmdFromTile(v, tile);
if ( cmd == (uint)-1) return;
if (DoCommandP(v->tile, v->index + (OrderGetSel(w) << 16), cmd, NULL, CMD_INSERT_ORDER | CMD_MSG(STR_8833_CAN_T_INSERT_NEW_ORDER))) {
if (WP(w,order_d).sel != -1)
WP(w,order_d).sel++;
ResetObjectToPlace();
}
}
static void OrdersWndProc(Window *w, WindowEvent *e)
{
switch(e->event) {
case WE_PAINT:
DrawOrdersWindow(w);
break;
case WE_CLICK: {
Vehicle *v = &_vehicles[w->window_number];
int mode;
switch(e->click.widget) {
case 2: {/* orders list */
int sel;
sel = (e->click.pt.y - 15) / 10;
if ( (uint) sel >= 6)
return;
sel += w->vscroll.pos;
if (sel == WP(w,order_d).sel) sel = -1;
WP(w,order_d).sel = sel;
SetWindowDirty(w);
} break;
case 4: /* skip button */
DoCommandP(v->tile,v->index, 0, NULL, CMD_SKIP_ORDER);
break;
case 5: /* delete button */
DoCommandP(v->tile,v->index, OrderGetSel(w), NULL, CMD_DELETE_ORDER | CMD_MSG(STR_8834_CAN_T_DELETE_THIS_ORDER));
break;
case 7: /* goto button */
InvalidateWidget(w, 7);
w->click_state ^= 1<<7;
if (HASBIT(w->click_state, 7)) {
_place_clicked_vehicle = NULL;
SetObjectToPlaceWnd(ANIMCURSOR_PICKSTATION, 1, w);
} else {
ResetObjectToPlace();
}
break;
case 8: /* full load button */
mode = 0;
DoCommandP(v->tile, v->index, OrderGetSel(w) | (mode << 8), NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
break;
case 9: /* unload button */
mode = 1;
DoCommandP(v->tile, v->index, OrderGetSel(w) | (mode << 8), NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
break;
case 6: /* non stop button */
mode = 2;
DoCommandP(v->tile, v->index, OrderGetSel(w) | (mode << 8), NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
break;
}
} break;
case WE_RCLICK: {
Vehicle *v = &_vehicles[w->window_number];
if (e->click.widget != 8) break;
if ((v->schedule_ptr[OrderGetSel(w)] & OT_MASK) == OT_GOTO_DEPOT)
GuiShowTooltips(STR_SERVICE_HINT);
else
GuiShowTooltips(STR_8857_MAKE_THE_HIGHLIGHTED_ORDER);
} break;
case WE_4: {
if (FindWindowById(WC_VEHICLE_VIEW, w->window_number) == NULL)
DeleteWindow(w);
} break;
case WE_PLACE_OBJ: {
OrdersPlaceObj(&_vehicles[w->window_number], e->place.tile, w);
} break;
case WE_ABORT_PLACE_OBJ: {
w->click_state &= ~(1<<7);
InvalidateWidget(w, 7);
} break;
// check if a vehicle in a depot was clicked..
case WE_MOUSELOOP: {
Vehicle *v = _place_clicked_vehicle;
if (v) {
_place_clicked_vehicle = NULL;
HandleOrderVehClick(&_vehicles[w->window_number], v, w);
}
} break;
}
}
static const Widget _train_orders_widgets[] = {
{ WWT_CLOSEBOX, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, 14, 11, 319, 0, 13, STR_8829_ORDERS, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PANEL, 14, 0, 308, 14, 75, 0x0, STR_8852_ORDERS_LIST_CLICK_ON_ORDER},
{ WWT_SCROLLBAR, 14, 309, 319, 14, 75, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
{ WWT_PUSHTXTBTN, 14, 0, 52, 76, 87, STR_8823_SKIP, STR_8853_SKIP_THE_CURRENT_ORDER},
{ WWT_PUSHTXTBTN, 14, 53, 105, 76, 87, STR_8824_DELETE, STR_8854_DELETE_THE_HIGHLIGHTED},
{ WWT_PUSHTXTBTN, 14, 106, 158, 76, 87, STR_8825_NON_STOP, STR_8855_MAKE_THE_HIGHLIGHTED_ORDER},
{WWT_NODISTXTBTN, 14, 159, 211, 76, 87, STR_8826_GO_TO, STR_8856_INSERT_A_NEW_ORDER_BEFORE},
{ WWT_PUSHTXTBTN, 14, 212, 264, 76, 87, STR_FULLLOAD_OR_SERVICE, 0},
{ WWT_PUSHTXTBTN, 14, 265, 319, 76, 87, STR_8828_UNLOAD, STR_8858_MAKE_THE_HIGHLIGHTED_ORDER},
{ WWT_LAST},
};
static const WindowDesc _train_orders_desc = {
-1,-1, 320, 88,
WC_VEHICLE_ORDERS,WC_VEHICLE_VIEW,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_RESTORE_DPARAM,
_train_orders_widgets,
OrdersWndProc
};
static const Widget _other_train_orders_widgets[] = {
{ WWT_CLOSEBOX, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, 14, 11, 319, 0, 13, STR_8829_ORDERS, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PANEL, 14, 0, 308, 14, 75, 0x0, STR_8852_ORDERS_LIST_CLICK_ON_ORDER},
{ WWT_SCROLLBAR, 14, 309, 319, 14, 75, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
{ WWT_LAST},
};
static const WindowDesc _other_train_orders_desc = {
-1,-1, 320, 76,
WC_VEHICLE_ORDERS,WC_VEHICLE_VIEW,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
_other_train_orders_widgets,
OrdersWndProc
};
static const Widget _roadveh_orders_widgets[] = {
{ WWT_TEXTBTN, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, 14, 11, 319, 0, 13, STR_900B_ORDERS, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_IMGBTN, 14, 0, 308, 14, 75, 0x0,STR_8852_ORDERS_LIST_CLICK_ON_ORDER},
{ WWT_SCROLLBAR, 14, 309, 319, 14, 75, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
{ WWT_PUSHTXTBTN, 14, 0, 63, 76, 87, STR_8823_SKIP, STR_8853_SKIP_THE_CURRENT_ORDER},
{ WWT_PUSHTXTBTN, 14, 64, 127, 76, 87, STR_8824_DELETE, STR_8854_DELETE_THE_HIGHLIGHTED},
{ WWT_EMPTY, 0, 0, 0, 0, 0, 0x0},
{WWT_NODISTXTBTN, 14, 128, 191, 76, 87, STR_8826_GO_TO, STR_8856_INSERT_A_NEW_ORDER_BEFORE},
{ WWT_PUSHTXTBTN, 14, 192, 255, 76, 87, STR_FULLLOAD_OR_SERVICE, 0},
{ WWT_PUSHTXTBTN, 14, 256, 319, 76, 87, STR_8828_UNLOAD, STR_8858_MAKE_THE_HIGHLIGHTED_ORDER},
{ WWT_LAST},
};
static const WindowDesc _roadveh_orders_desc = {
-1,-1, 320, 88,
WC_VEHICLE_ORDERS,WC_VEHICLE_VIEW,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_RESTORE_DPARAM,
_roadveh_orders_widgets,
OrdersWndProc
};
static const Widget _other_roadveh_orders_widgets[] = {
{ WWT_TEXTBTN, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, 14, 11, 319, 0, 13, STR_900B_ORDERS, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_IMGBTN, 14, 0, 308, 14, 75, 0x0,STR_8852_ORDERS_LIST_CLICK_ON_ORDER},
{ WWT_SCROLLBAR, 14, 309, 319, 14, 75, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
{ WWT_LAST},
};
static const WindowDesc _other_roadveh_orders_desc = {
-1,-1, 320, 76,
WC_VEHICLE_ORDERS,WC_VEHICLE_VIEW,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
_other_roadveh_orders_widgets,
OrdersWndProc
};
static const Widget _ship_orders_widgets[] = {
{ WWT_TEXTBTN, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, 14, 11, 319, 0, 13, STR_9810_ORDERS, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_IMGBTN, 14, 0, 308, 14, 75, 0x0,STR_8852_ORDERS_LIST_CLICK_ON_ORDER},
{ WWT_SCROLLBAR, 14, 309, 319, 14, 75, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
{ WWT_PUSHTXTBTN, 14, 0, 63, 76, 87, STR_8823_SKIP, STR_8853_SKIP_THE_CURRENT_ORDER},
{ WWT_PUSHTXTBTN, 14, 64, 127, 76, 87, STR_8824_DELETE, STR_8854_DELETE_THE_HIGHLIGHTED},
{ WWT_EMPTY, 0, 0, 0, 0, 0, 0x0},
{WWT_NODISTXTBTN, 14, 128, 191, 76, 87, STR_8826_GO_TO, STR_8856_INSERT_A_NEW_ORDER_BEFORE},
{ WWT_PUSHTXTBTN, 14, 192, 255, 76, 87, STR_FULLLOAD_OR_SERVICE, 0},
{ WWT_PUSHTXTBTN, 14, 256, 319, 76, 87, STR_8828_UNLOAD, STR_8858_MAKE_THE_HIGHLIGHTED_ORDER},
{ WWT_LAST},
};
static const WindowDesc _ship_orders_desc = {
-1,-1, 320, 88,
WC_VEHICLE_ORDERS,WC_VEHICLE_VIEW,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_RESTORE_DPARAM,
_ship_orders_widgets,
OrdersWndProc
};
static const Widget _other_ship_orders_widgets[] = {
{ WWT_TEXTBTN, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, 14, 11, 319, 0, 13, STR_9810_ORDERS, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_IMGBTN, 14, 0, 308, 14, 75, 0x0,STR_8852_ORDERS_LIST_CLICK_ON_ORDER},
{ WWT_SCROLLBAR, 14, 309, 319, 14, 75, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
{ WWT_LAST},
};
static const WindowDesc _other_ship_orders_desc = {
-1,-1, 320, 76,
WC_VEHICLE_ORDERS,WC_VEHICLE_VIEW,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
_other_ship_orders_widgets,
OrdersWndProc
};
static const Widget _aircraft_orders_widgets[] = {
{ WWT_TEXTBTN, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, 14, 11, 319, 0, 13, STR_A00B_ORDERS, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_IMGBTN, 14, 0, 308, 14, 75, 0x0, STR_8852_ORDERS_LIST_CLICK_ON_ORDER},
{ WWT_SCROLLBAR, 14, 309, 319, 14, 75, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
{ WWT_PUSHTXTBTN, 14, 0, 63, 76, 87, STR_8823_SKIP, STR_8853_SKIP_THE_CURRENT_ORDER},
{ WWT_PUSHTXTBTN, 14, 64, 127, 76, 87, STR_8824_DELETE, STR_8854_DELETE_THE_HIGHLIGHTED},
{ WWT_EMPTY, 0, 0, 0, 0, 0, 0x0},
{WWT_NODISTXTBTN, 14, 128, 191, 76, 87, STR_8826_GO_TO, STR_8856_INSERT_A_NEW_ORDER_BEFORE},
{ WWT_PUSHTXTBTN, 14, 192, 255, 76, 87, STR_FULLLOAD_OR_SERVICE, 0},
{ WWT_PUSHTXTBTN, 14, 256, 319, 76, 87, STR_8828_UNLOAD, STR_8858_MAKE_THE_HIGHLIGHTED_ORDER},
{ WWT_LAST},
};
static const WindowDesc _aircraft_orders_desc = {
-1,-1, 320, 88,
WC_VEHICLE_ORDERS,WC_VEHICLE_VIEW,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_RESTORE_DPARAM,
_aircraft_orders_widgets,
OrdersWndProc
};
static const Widget _other_aircraft_orders_widgets[] = {
{ WWT_TEXTBTN, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, 14, 11, 319, 0, 13, STR_A00B_ORDERS, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_IMGBTN, 14, 0, 308, 14, 75, 0x0, STR_8852_ORDERS_LIST_CLICK_ON_ORDER},
{ WWT_SCROLLBAR, 14, 309, 319, 14, 75, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
{ WWT_LAST},
};
static const WindowDesc _other_aircraft_orders_desc = {
-1,-1, 320, 76,
WC_VEHICLE_ORDERS,WC_VEHICLE_VIEW,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
_other_aircraft_orders_widgets,
OrdersWndProc
};
static const WindowDesc * const _order_window_desc[8] = {
&_train_orders_desc, &_other_train_orders_desc,
&_roadveh_orders_desc, &_other_roadveh_orders_desc,
&_ship_orders_desc, &_other_ship_orders_desc,
&_aircraft_orders_desc, &_other_aircraft_orders_desc,
};
void ShowOrdersWindow(Vehicle *v)
{
Window *w;
VehicleID veh = v->index;
DeleteWindowById(WC_VEHICLE_ORDERS, veh);
DeleteWindowById(WC_VEHICLE_DETAILS, veh);
_alloc_wnd_parent_num = veh;
w = AllocateWindowDesc(
_order_window_desc[(v->type - VEH_Train)*2 + (v->owner != _local_player)]);
w->window_number = veh;
w->caption_color = v->owner;
w->vscroll.cap = 6;
WP(w,order_d).sel = -1;
}

Binary file not shown.

@ -0,0 +1,55 @@
//
// OpenTTDMidi.java
// OpenTTDMidi
//
// Created by Joshua King on Sun Apr 25 2004.
// Copyright (c) 2004 __MyCompanyName__. All rights reserved.
//
import java.io.*;
import java.util.*;
import javax.sound.midi.*;
public class OpenTTDMidi {
public static void main (String args[]) {
// Currently command line is the MIDI file
if (args.length == 1) {
Sequencer s2 = null;
try {
s2 = MidiSystem.getSequencer();
s2.open();
} catch (MidiUnavailableException mue) {
System.exit(1);
}
Sequence s = null;
try {
s = MidiSystem.getSequence(new File(args[0]));
} catch (InvalidMidiDataException imde) {
System.exit(2);
} catch (IOException ioe) {
System.exit(3);
}
try {
s2.setSequence(s);
s2.setMicrosecondPosition(0);
s2.start();
for (long l = 0; l < (s.getMicrosecondLength() / 1000000); l++) {
try {
//System.out.print(".");
Thread.currentThread().sleep(1000);
} catch (InterruptedException ie) {}
}
System.out.println();
} catch (InvalidMidiDataException imde) {
}
s2.stop();
s2.close();
System.exit(0);
}
}
}

@ -0,0 +1,45 @@
#!/bin/sh
# sets VERSION to the value if RELEASE if there are any,
# otherwise it sets VERSION to revision number
if [ "$3" ]; then
VERSION="$3"
else
VERSION="$2"
fi
# Generates Info.plist while applying $VERSION
echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\"
\"http://www.apple.com/DTDs/Prop$
<plist version=\"1.0\">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleDisplayName</key>
<string>Open Transport Tycoon</string>
<key>CFBundleExecutable</key>
<string>ttd</string>
<key>CFBundleGetInfoString</key>
<string>$VERSION, Copyright 2004 The Open Transport Tycoon team</string>
<key>CFBundleIconFile</key>
<string>ttd.icns</string>
<key>CFBundleIdentifier</key>
<string>org.ludde-ottd.ludde-ottd</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>ottd</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$VERSION</string>
<key>CFBundleVersion</key>
<string>$VERSION</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright 2004 The Open Transport Tycoon team</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
</dict>
</plist>" > "$1"/contents/Info.plist

@ -0,0 +1,2 @@
#!/bin/bash
exec /usr/bin/java -cp OpenTTD.app/contents/macos OpenTTDMidi "$1"

Binary file not shown.

@ -0,0 +1,26 @@
; Ini file generated by the HM NIS Edit IO designer.
[Settings]
NumFields=3
[Field 1]
Type=Groupbox
Text=Transport Tycoon Deluxe Installation location
Left=0
Right=288
Top=68
Bottom=100
[Field 2]
Type=DirRequest
Left=4
Right=282
Top=80
Bottom=92
[Field 3]
Type=Label
Left=13
Right=278
Top=6
Bottom=64

@ -0,0 +1,38 @@
; Ini file generated by the HM NIS Edit IO designer.
[Settings]
NumFields=4
[Field 1]
Type=Button
Text=Instant Install
Flags=NOTIFY
Left=0
Right=58
Top=0
Bottom=15
[Field 2]
Type=Button
Text=Advanced Install
Flags=NOTIFY
Left=0
Right=58
Top=19
Bottom=35
[Field 3]
Type=Label
Text=Install OpenTTD instantly and quickly, no questions asked
Left=62
Right=245
Top=3
Bottom=11
[Field 4]
Type=Label
Text=In case you want to change location, options, Start Menu location, etc
Left=62
Right=283
Top=23
Bottom=31

@ -0,0 +1,14 @@
TTD to OpenTTD
Transition Guide
This guide gives you pointers in making the transition from TTD to OpenTTD. Once OpenTTD matures more, this guide will grow. For now, here are the major differences that Ive seen.
* Being able to resize the window so that "full-screen" can also show so much more of the land
* Command Line switches to make things easier
* Generate Random Land in the scenario editor also builds small towns, forests, and industries
* A configuration screen that lets you turn on / off TTD Patch features
Some day, OpenTTD will contain the features of TTD Patch.
Created by RaggieSoft TallwoodBand@cox.net
Guide Version: 0.1.1
Supports OpenTTD Version: 0.2.1
Send your ideas for this document to my email address. I also maintain an accunt with tt-forums.net. It's RaggieSoft.

@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
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
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
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 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
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
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
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
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
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
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
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
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
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
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
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
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
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
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
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
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 Library General
Public License instead of this License.

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

Loading…
Cancel
Save