importing devsrv CVS to Savannah CVS

This commit is contained in:
uid66289 2003-12-23 22:45:30 +00:00
parent 15574b6539
commit b1c76bcb5b
113 changed files with 5480 additions and 1412 deletions

View file

@ -1,48 +1,56 @@
/* $Id$ */
Kontroller
* Piltaster: Panorer
Piltaster: Panorer
* Venstreklikk: Velg enhet/flytt enhet
Venstreklikk: Velg enhet/flytt enhet
* Høyreklikk: Hovedmeny, avbryt handling
Høyreklikk: Hovedmeny, avbryt handling
* Escape: Avslutt spill
Tredje museknapp: Sentrer på peker
* z: Zoom inn
Escape: Avslutt spill
* x: Zoom ut
z: Zoom inn
* c: Standard zoom-nivå
x: Zoom ut
* u: Angre siste trekk (bare deterministiske flytt kan omgjøres)
c: Standard zoom-nivå
* r: Gjenta trekk
u: Angre siste trekk (bare deterministiske flytt kan omgjøres)
* n: Gå gjennom alle enheter som kan flytte
r: Gjenta trekk
* l: Gå til lederenhet
n: Gå gjennom alle enheter som kan flytte
* space: Avslutt runden for denne enheten, og gå videre til neste enhet som kan flytte
1-7: Vis hvor langt valgte enhet kan flytte på x antall runder
* ctrl-f: Bytt mellom fullskjerm- og vindumodus
space: Avslutt runden for denne enheten, og gå videre til neste enhet som kan flytte
* ctrl-r: Rekrutter enhet
l: Gå til lederenhet
* ctrl-c: Tilbakekall enhet
ctrl-f: Bytt mellom fullskjerm- og vindumodus
* ctrl-a: Skru på/av akselerert spillmodus
ctrl-r: Rekrutter enhet
* d: Beskriv valgte enhet
ctrl-shift-r: Gjenta siste rekruttering
* ctrl-d: Studer den valgte enhets motstand mot angrep
ctrl-c: Tilbakekall enhet
* ctrl-t: Studer hvordan den valgte enhet takler forskjellige typer terreng
ctrl-a: Skru på/av akselerert spillmodus
* ctrl-s: Lagre spill
d: Beskriv valgte enhet
ctrl-d: Studer den valgte enhets motstand mot angrep
ctrl-t: Studer hvordan den valgte enhet takler forskjellige typer terreng
ctrl-s: Lagre spill
@ -52,7 +60,7 @@ Lyskuler
Hvordan kan jeg se om en enhet er venn eller fiende? På toppen av energiindikatoren som finnes ved siden av hver enhet er det en lyskule. Denne lyskulen forteller:
På toppen av livsindikatoren som finnes ved siden av hver enhet er det en lyskule. Denne lyskulen er:
@ -64,9 +72,9 @@ Hvordan kan jeg se om en enhet er venn eller fiende? P
* blå hvis enheten tilhører en alliert, men ikke er kontrollert av deg
* svart hvis enheten er fiendtlig
Fiendtlige enheter har ingen lyskule på toppen av livsindikatoren. (I tidligere versjoner < 0.5.2 var det en svart kule på toppen av livsindikatoren til fiendtlige enheter)
@ -80,11 +88,27 @@ Spillet skjer gjennom en serie kamper, eller scenario. Hvert scenario setter din
Gull
Hver side blir gitt et beløp gull i begynnelsen, og mottar så 2 gullstykker per runde, pluss 2 gullstykker for hver landsby som kontrolleres. Hver side må betale 1 gullstykke i underhold hver runde per enhet på slagmarken.
Hver side blir gitt et beløp gull i begynnelsen, og mottar så 2 gullstykker per runde, pluss 2 gullstykker for hver landsby som kontrolleres.
Hver enhet har også en underholdskostnad. Denne kostnader er generelt lik nivået til enheten (men se karaktertrekket 'Lojal' under). Enheter som ikke blir tilbakekalt eller rekruttert - det vil si, enheter som leder en side eller blir med frivillig - har ingen underholdskostnad. Underhold blir bare betalt hvis totalt underhold for enhetene til en side er større enn antall landsbyer den siden kontrollerer. Underhold som blir betalt er differansen mellom antall landsbyer og underholdskostnaden. Formelen for å bestemme inntekt per runde blir derfor:
2 + antall landsbyer - maksimum(0, underhold - landsbyer)
hvor underhold er lik summen av nivåene til alle enheter som har blitt tilbakekalt eller rekruttert.
@ -104,11 +128,41 @@ Du kan f
Du kan ikke flytte en enhet samme runde som den blir rekruttert eller tilbakekalt.
Enhetsspesialiteter
Enhetsspesialiteter er beskrevet under Beskrivelse i hovedmenyen.
Enhetsspesialiteter er beskrevet under Beskrivelse inne i selve spillet.
Karaktertrekk
Enheter har personlige egenskaper som reflekterer deres karakter. Karaktertrekk blir tildelt enheter tilfeldig når hyres. Hver enhet får tildelt to karaktertrekk. Mulige karaktertrekk er som følger:
Lojal: Enheten betaler aldri mer en 1 i underhold.
Sterk: Enheten gjør ekstra skade i nærkamp, og har noen ekstra livspoeng.
Rask: Enheten kan flytte en ekstra rute, men har litt færre livspoeng.
Motstandsdyktig: Enheten har flere livspoeng.
Intelligent: Enheten trenger færre erfaringspoeng for å avansere til et høyere nivå.
@ -120,6 +174,12 @@ N
Du kan ikke flytte gjennom de seks rutene rundt en motstander (deres Kontrollsone) uten å stoppe.
Kamp
@ -140,6 +200,8 @@ Hver enhet har en viss sjanse for
Holdning
@ -148,10 +210,6 @@ Hver enhet har en holdning: lovlydig, n
| runde | tid |
-------------------------
@ -170,19 +228,23 @@ Hver enhet har en holdning: lovlydig, n
Lovlydige enheter gjør 25% mer skade om dagen, og 25% mindre om natten. Kaotiske enheter gjør 25% mer skade om natten, og 25% mindre om dagen. Nøytrale enheter blir ikke påvirket av dag/natt syklusen.
Helbredelse
Skadde enheter i landsbyer vil heles 8 livspoeng hver runde. Skadde enheter ved siden av enheter med 'helbrede' eller 'kurere' egenskaper vil også bli helbredet. Enheter ved siden av enheter som har 'helbrede' som egenskap vil heles maksimum 4 livspoeng per runde, og 8 livspoeng per runde for enheter som har 'kurere' som egenskap. Jo flere enheter det er rundt en helbredende enhet, jo mindre vil hver bli helbredet.
Skadde enheter i landsbyer vil heles 8 livspoeng hver runde. Skadde enheter ved siden av enheter som innehar 'helbreder' eller 'kurerer' -evner vil også bli helbredet. Enheter ved siden av enheter som har 'helbreder' som evne vil heles maksimum 4 livspoeng per runde, og 8 livspoeng per runde for enheter som har 'kurerer' som evne. Jo flere enheter det er rundt en helbredende enhet, jo mindre vil hver bli helbredet.
'Helbreder' gjør at forgiftning ikke gjør skade, mens 'kurerer' fjerner forgiftningen helt. Når forgiftning blir kurert får ikke enheten som blir kurert tilbake livspoeng den runden.
@ -194,5 +256,41 @@ Enheter f
/* $Id$ */
Flerspiller
Det er også flere måter å delta i en flerspiller-omgang med Wesnoth. Den enkleste måten er et 'samme-stol' spill: Flere spillere spiller på samme PC, det hver spiller overtar når det er hans tur. For å starte et 'samme-stol' spill, velg 'Flerspiller' fra hovedmenyen -> 'Vert for flerspiller'. Etter å ha valgt kart, endre alle navnene i 'Spillertype' til å være menneske eller datastyrte spillere (altså ingen 'Nettverksspillere'), og start så spillet.
Du kan også spille Wesnoth over nettverk. En spiller bruker sin PC som 'vert', og andre spillere henger seg på. Velg 'Flerspiller' -> 'Vert for flerspiller', og endre så noen av 'Spillertype' boksene til 'Nettverksspiller'. Når du har startet spillet, vil det vente på at andre spillere skal henge seg på. De andre spillerne må velge 'Flerspiller' -> 'Bli med i spill', og så skrive navnet til vertsmaskinen eller IP-adressen til spilleren som er vert.
Når alle spillerne har hengt seg på begynner spillet. Spilleren som er vert må være i stand til å motta forbindelser til port 15000. De andre spillerne må kunne binde seg til port 15000 på en ekstern maskin. Du kan bare spille spill over nettverk mot spillere som har eksakt samme versjon av spillet som deg.
Du kan også spille spill på Wesnoths egne tjenere. Wesnoth har to offentlig tilgjengelige tjenere:
server.wesnoth.org: for utgitte versjoner av spillet
devsrv.wesnoth.org: for CVS versjoner av spillet (versjoner under utvikling)
For å koble til tjeneren, velg 'Flerspiller' -> 'Bli med i spill' og skriv så vertsnavnet til tjeneren. Du må bruke nøyaktig den versjonen av spillet som tjeneren er satt opp for å bruke, for å få lov til å spille.
Når du er tilkoblet tjeneren, blir du plasser i et 'vestibyle'. I vestibylen kan du se hvilke andre spillere som er på nett, hvilke spill som er tilgjengelige, og starte nye spill. En spiller starter et nytt spillet, så kan de andre spillerne henge seg på.
Det er mulig å bare observere et pågående spill, ved å bli med i spillet som en 'Observatør'.

View file

@ -1,5 +1,10 @@
AUTOMAKE_OPTIONS = foreign
SUBDIRS = src
if ICONS
ISUBDIRS = icons
else
ISUBDIRS =
endif
SUBDIRS = src $(ISUBDIRS)
pkgdatadir=$(datadir)/@DATADIR@
dist_noinst_DATA = @MANUAL_FILES@ copyright changelog @UTIL_FILES@

View file

@ -1,4 +1,4 @@
# Makefile.in generated by automake 1.7.9 from Makefile.am.
# Makefile.in generated by automake 1.7.8 from Makefile.am.
# @configure_input@
# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
@ -64,11 +64,22 @@ EDITOR_TRUE = @EDITOR_TRUE@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
FONT_FILES = @FONT_FILES@
GNOME1_DESKTOP = @GNOME1_DESKTOP@
GNOME1_FALSE = @GNOME1_FALSE@
GNOME1_TRUE = @GNOME1_TRUE@
GNOME_CONFIG = @GNOME_CONFIG@
ICONS_FALSE = @ICONS_FALSE@
ICONS_TRUE = @ICONS_TRUE@
IMAGE_FILES = @IMAGE_FILES@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
KDE_CONFIG = @KDE_CONFIG@
KDE_DESKTOP = @KDE_DESKTOP@
KDE_FALSE = @KDE_FALSE@
KDE_ICON = @KDE_ICON@
KDE_TRUE = @KDE_TRUE@
LDFLAGS = @LDFLAGS@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
@ -131,7 +142,9 @@ sharedstatedir = @sharedstatedir@
sysconfdir = @sysconfdir@
target_alias = @target_alias@
AUTOMAKE_OPTIONS = foreign
SUBDIRS = src
@ICONS_TRUE@ISUBDIRS = icons
@ICONS_FALSE@ISUBDIRS =
SUBDIRS = src $(ISUBDIRS)
dist_noinst_DATA = @MANUAL_FILES@ copyright changelog @UTIL_FILES@
nobase_dist_pkgdata_DATA = @DATA_FILES@ @FONT_FILES@ @IMAGE_FILES@ @MUSIC_FILES@ @SOUND_FILES@
@ -158,7 +171,7 @@ DIST_COMMON = README $(dist_man6_MANS) $(dist_noinst_DATA) \
$(srcdir)/configure COPYING INSTALL Makefile.am aclocal.m4 \
config.h.in configure configure.ac depcomp install-sh missing \
mkinstalldirs
DIST_SUBDIRS = $(SUBDIRS)
DIST_SUBDIRS = src icons
all: config.h
$(MAKE) $(AM_MAKEFLAGS) all-recursive
@ -430,7 +443,7 @@ distdir: $(DISTFILES)
|| exit 1; \
fi; \
done
list='$(SUBDIRS)'; for subdir in $$list; do \
list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
if test "$$subdir" = .; then :; else \
test -d $(distdir)/$$subdir \
|| mkdir $(distdir)/$$subdir \
@ -530,7 +543,7 @@ install-am: all-am
installcheck: installcheck-recursive
install-strip:
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
INSTALL_STRIP_FLAG=-s \
`test -z '$(STRIP)' || \
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
mostlyclean-generic:

View file

@ -1,3 +1,29 @@
Version 0.6.2:
* extended tutorial
* two new music tracks
* new scenarios for 'The Dark Hordes' campaign:
* Mages and Elves
* scenario balancing for 'Dark Hordes' campaign:
* Brother Against Brother
* The Skull of Agarash
* multiplayer improvements:
* added basic random map generator
* made basic messaging possible using 'Speak' from main menu
* medium difficulty level is used by default when starting new campaign
* snapshot saving, faster loading if you skip replay
* more unit graphics and animations
* undeads can not be drained anymore
* fixed description for 'Wolf Rider'
* updated translations:
* dutch
* internationalization: string fixes
* fixed client-hosted multiplayer bug where more than two player games were not possible
* fixed problem with saving at the end of the scenario pointing to the previous scenario
* autotools: checks for png support in sdl_image and ogg support in sdl_mixer
* autotools: application icon and menu entries in KDE and GNOME
* improved speed of reading cfg-files
* code refactoring
Version 0.6.1:
* removed plague ability from Wraiths
* decreased Lich's melee damage by one

View file

@ -1,156 +1,104 @@
/* config.h.in. Generated from configure.ac by autoheader. */
/*
Define to 1 if you have the <dirent.h>
header file, and it defines `DIR'. */
/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.
*/
#undef HAVE_DIRENT_H
/*
Define to 1 if you have the `floor'
function. */
/* Define to 1 if you have the `floor' function. */
#undef HAVE_FLOOR
/*
Define to 1 if you have the <inttypes.h>
header file. */
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/*
Define to 1 if you have the <memory.h>
header file. */
/* Define to 1 if you have the `SDL_mixer' library (-lSDL_mixer). */
#undef HAVE_LIBSDL_MIXER
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/*
Define to 1 if you have the <ndir.h>
header file, and it defines `DIR'. */
/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
#undef HAVE_NDIR_H
/*
Define to 1 if you have the `socket'
function. */
/* Define to 1 if you have the `socket' function. */
#undef HAVE_SOCKET
/*
Define to 1 if `stat' has the bug
that it succeeds when given the zero-length file name
argument. */
/* Define to 1 if `stat' has the bug that it succeeds when given the
zero-length file name argument. */
#undef HAVE_STAT_EMPTY_STRING_BUG
/*
Define to 1 if stdbool.h conforms to C99.
*/
/* Define to 1 if stdbool.h conforms to C99. */
#undef HAVE_STDBOOL_H
/*
Define to 1 if you have the <stdint.h>
header file. */
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
/*
Define to 1 if you have the <stdlib.h>
header file. */
/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
/*
Define to 1 if you have the `strftime'
function. */
/* Define to 1 if you have the `strftime' function. */
#undef HAVE_STRFTIME
/*
Define to 1 if you have the <strings.h>
header file. */
/* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
/*
Define to 1 if you have the <string.h>
header file. */
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
/*
Define to 1 if you have the `strtoul'
function. */
/* Define to 1 if you have the `strtoul' function. */
#undef HAVE_STRTOUL
/*
Define to 1 if you have the <sys/dir.h>
header file, and it defines `DIR'. */
/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
*/
#undef HAVE_SYS_DIR_H
/*
Define to 1 if you have the <sys/ndir.h>
header file, and it defines `DIR'. */
/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.
*/
#undef HAVE_SYS_NDIR_H
/*
Define to 1 if you have the <sys/stat.h>
header file. */
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
/*
Define to 1 if you have the <sys/types.h>
header file. */
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
/*
Define to 1 if you have the <unistd.h>
header file. */
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/*
Define to 1 if the system has the
type `_Bool'. */
/* Define to 1 if the system has the type `_Bool'. */
#undef HAVE__BOOL
/*
Define to 1 if `lstat' dereferences a symlink
specified with a trailing slash. */
/* Define to 1 if `lstat' dereferences a symlink specified with a trailing
slash. */
#undef LSTAT_FOLLOWS_SLASHED_SYMLINK
/*
Name of package */
/* Name of package */
#undef PACKAGE
/*
Define to the address where bug reports for
this package should be sent. */
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
/*
Define to the full name of this package.
*/
/* Define to the full name of this package. */
#undef PACKAGE_NAME
/*
Define to the full name and version of
this package. */
/* Define to the full name and version of this package. */
#undef PACKAGE_STRING
/*
Define to the one symbol short name of
this package. */
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/*
Define to the version of this package. */
/* Define to the version of this package. */
#undef PACKAGE_VERSION
/*
Define to 1 if you have the ANSI
C header files. */
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
/*
Define to 1 if your <sys/time.h> declares `struct
tm'. */
/* Define to 1 if your <sys/time.h> declares `struct tm'. */
#undef TM_IN_SYS_TIME
/*
Version number of package */
/* Version number of package */
#undef VERSION
/*
Define to empty if `const' does not conform
to ANSI C. */
/* Define to empty if `const' does not conform to ANSI C. */
#undef const
/* Define to `__inline__' or `__inline' if that's what the C compiler
@ -159,12 +107,8 @@
#undef inline
#endif
/*
Define to `int' if <sys/types.h> does not define.
*/
/* Define to `int' if <sys/types.h> does not define. */
#undef mode_t
/*
Define to `unsigned' if <sys/types.h> does not define.
*/
/* Define to `unsigned' if <sys/types.h> does not define. */
#undef size_t

672
configure vendored

File diff suppressed because it is too large Load diff

View file

@ -1,13 +1,17 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.57)
AC_INIT(wesnoth, 0.8, davidnwhite@optusnet.com.au, Battle for Wesnoth)
#######################################################################
# Initial configuration #
#######################################################################
AC_REVISION($Version: 0.8$)
AC_PREREQ(2.57)
AC_INIT(wesnoth, 0.11, davidnwhite@optusnet.com.au, Battle for Wesnoth)
AC_REVISION($Version: 0.11$)
PACKAGE=wesnoth
MAJOR_VERSION="0"
MINOR_VERSION="6"
MICRO_VERSION="1"
MICRO_VERSION="2-CVS"
if test "x$MICRO_VERSION" = "x"; then
VERSION=$MAJOR_VERSION.$MINOR_VERSION
@ -19,23 +23,63 @@ AM_INIT_AUTOMAKE($PACKAGE, $VERSION)
AC_CONFIG_SRCDIR([src/actions.cpp])
AC_CONFIG_HEADER([config.h])
# Checks for programs.
#######################################################################
# Checks for programs. #
#######################################################################
AC_PROG_CXX
AC_PROG_CC
# SDL_CONFIG
AC_PATH_PROGS(SDL_CONFIG, [sdl-config sdl11-config], none)
if test "x$SDL_CONFIG" = "xnone"; then
AC_MSG_ERROR([*** SDL not found! Get SDL from www.libsdl.org.
AC_MSG_ERROR([*** SDL not found! Get SDL from www.libsdl.org.
If you already installed it, check it's in the path. If problem remains,
please send a mail to the address that appears in ./configure --version
indicating your platform, the version of configure script and the problem.])
fi
# Checks for libraries.
# GNOME_CONFIG
AC_PATH_PROGS([GNOME_CONFIG], [gnome-config], [none])
if test "x$GNOME_CONFIG" = "xnone"; then
gnome1=no
else
GNOME1_DESKTOP=`$GNOME_CONFIG --datadir`/gnome/apps/Games
gnome1=yes
fi
AC_SUBST([GNOME1_DESKTOP])
AM_CONDITIONAL(GNOME1, test x$gnome1 = xyes)
# KDE_CONFIG
AC_PATH_PROGS(KDE_CONFIG, kde-config, none)
if test "x$KDE_CONFIG" = "xnone"; then
kde=no
else
KDE_DESKTOP=`$KDE_CONFIG --expandvars --install apps`/Games/TacticStrategy
KDE_ICON=`$KDE_CONFIG --expandvars --install icon`
kde=yes
fi
AC_SUBST([KDE_DESKTOP])
AC_SUBST([KDE_ICON])
AM_CONDITIONAL(KDE, test x$kde = xyes)
#######################################################################
# Checks for libraries. #
#######################################################################
SDL_LIBS=`$SDL_CONFIG --libs`
OLD_LIBS=$LIBS
@ -50,7 +94,7 @@ AC_CHECK_LIB([SDL_image],
[SDL_IMAGE_LIBS=-lSDL_image],
[AC_MSG_ERROR([*** SDL_image lib not found! Get SDL_image from
http://www.libsdl.org/projects/SDL_image/index.html])])
AC_CHECK_LIB([SDL_mixer],
[Mix_OpenAudio],
[SDL_MIXER_LIBS=-lSDL_mixer],
@ -77,7 +121,11 @@ AC_SUBST([SDL_MIXER_LIBS])
AC_SUBST([SDL_NET_LIBS])
AC_SUBST([SDL_TTF_LIBS])
# Checks for header files.
#######################################################################
# Checks for header files. #
#######################################################################
AC_HEADER_DIRENT
AC_HEADER_STDC
@ -121,7 +169,11 @@ AC_SUBST([SDL_CFLAGS])
AC_CHECK_HEADERS([stdlib.h unistd.h])
# Checks for typedefs, structures, and compiler characteristics.
#######################################################################
# Checks for typedefs, structures, and compiler characteristics. #
#######################################################################
AC_HEADER_STDBOOL
AC_C_CONST
AC_C_INLINE
@ -135,6 +187,64 @@ AC_FUNC_STAT
AC_FUNC_STRFTIME
AC_CHECK_FUNCS([floor socket strtoul])
#######################################################################
# Check for PNG support in SDL_image #
#######################################################################
AC_MSG_CHECKING([for PNG support in SDL_image])
OLD_CPPFLAGS=$CPPFLAGS
OLD_CXXFLAGS=$CXXFLAGS
OLD_LIBS=$LIBS
CPPFLAGS="$CFLAGS $SDL_CFLAGS"
CXXFLAGS="$CFLAGS $SDL_CFLAGS"
LIBS="$LIBS $SDL_LIBS $SDL_IMAGE_LIBS"
AC_TRY_RUN([
#include <SDL_image.h>
#include <stdlib.h>
int main(void)
{
SDL_RWops *src;
src = SDL_RWFromFile("images/mage.png", "rb");
if (src == NULL)
exit(0);
exit(!IMG_isPNG(src));
}
],
[AC_MSG_RESULT(yes)],
[AC_MSG_RESULT(no)]
[AC_MSG_ERROR([*** SDL_image has no PNG support! You need SDL_image with PNG support])],
[AC_MSG_RESULT[not tested in cross-compiling]])
CPPFLAGS=$OLD_CPPFLAGS
CXXFLAGS=$OLD_CXXFLAGS
LIBS=$OLD_LIBS
#######################################################################
# Check for OGG support in SDL_mixer #
#######################################################################
OLD_LIBS=$LIBS
LIBS="$LIBS $SDL_LIBS $SDL_MIXER_LIBS"
AC_CHECK_LIB([SDL_mixer],
[OGG_new],
,
[AC_MSG_WARN([*** SDL_mixer has no OGG support. You won't have music in the game.])])
LIBS=$OLD_LIBS
#######################################################################
# Configuration options #
#######################################################################
AC_ARG_ENABLE(debug,
[ --enable-debug Enable debug in wesnoth],
CXXFLAGS="$CXXFLAGS -DDEBUG -ggdb3")
@ -172,9 +282,27 @@ AC_ARG_ENABLE(tools,
[ --enable-tools Enable compilation of translation tools],
tools=yes)
AC_ARG_ENABLE(icons,
[ --disable-icons Disable installation of icons and menu entries],
icons=$enableval,
icons=yes)
AM_CONDITIONAL(SERVER, test x$server = xyes)
AM_CONDITIONAL(EDITOR, test x$editor = xyes)
AM_CONDITIONAL(TOOLS, test x$tools = xyes)
AM_CONDITIONAL(ICONS, test x$icons = xyes)
#######################################################################
# Icon and menu handling #
#######################################################################
#######################################################################
# Data file substitution. #
#######################################################################
MANUAL_FILES=`ls MANUAL*`
MANUAL_FILES=`echo $MANUAL_FILES`
@ -199,7 +327,9 @@ AC_SUBST([MUSIC_FILES])
AC_SUBST([SOUND_FILES])
AC_SUBST([UTIL_FILES])
AC_CONFIG_FILES([Makefile
icons/Makefile
src/Makefile
src/server/Makefile
src/tools/Makefile])

View file

@ -10,6 +10,45 @@
{items.cfg}
{terrain_generator.cfg}
[game_config]
base_income=2
village_income=1
heal_amount=4
healer_heals_per_turn=8
cure_amount=8
curer_heals_per_turn=18
recall_cost=20
kill_experience=8
title="title.png"
icon="wesnoth-icon.png"
title_music="wesnoth-7.ogg"
map_image="misc/map.png"
sidebar_image="misc/rightside.png"
sidebar_image_bottom="misc/rightside-bottom.png"
moved_energy_image="moved-energy.png"
unmoved_energy_image="unmoved-energy.png"
partmoved_energy_image="partmoved-energy.png"
enemy_energy_image="enemy-energy.png"
ally_energy_image="ally-energy.png"
cross_image="misc/cross.png"
dot_image="misc/dot.png"
footprint_left_nw=misc/foot-left-nw.png
footprint_left_n=misc/foot-left-n.png
footprint_right_nw=misc/foot-right-nw.png
footprint_right_n=misc/foot-right-n.png
missile_n_image=missile-n.png
missile_ne_image=missile-ne.png
[/game_config]
[campaign]
id=heir_throne
name=Heir to the Throne
@ -356,7 +395,7 @@
[movement costs]
deep water=100
shallow water=3
swamp water=3
swamp water=2
grassland=1
sand=2
forest=1
@ -372,7 +411,7 @@
[defense]
deep water=80
shallow water=70
swamp water=70
swamp water=60
grassland=60
sand=70
forest=30
@ -395,6 +434,7 @@
[/movetype]
[movetype]
name=woodlandfloat
flies=true
[movement costs]
deep water=2
shallow water=1
@ -438,6 +478,7 @@
[movetype]
name=fly
flies=true
[movement costs]
deep water=1
shallow water=1
@ -610,6 +651,7 @@
[movetype]
name=undeadfly
flies=true
[movement costs]
deep water=1
shallow water=1
@ -654,5 +696,6 @@
[/units]
{tutorial.cfg}
{tutorial2.cfg}
{scenarios}
{scenario-test.cfg}

View file

@ -1,4 +1,5 @@
[story]
music=wesnoth-1.ogg
[part]
id=intro_1
story="In the twenty-seventh year of Garard II, king of Wesnoth, the kingdom was plunged into a bitter war with the Northern peoples."

View file

@ -1,16 +1,3 @@
ggfffffffgggggggggggg
ggfffffffgtgggggggggg
ggfffffffCggggggggggg
ggfffffft1Cgggggggggg
ggfffffffCCgggggggggg
ggggggggCCCgggggggggg
ggggggggC2ggggggggggg
ggggggggggggggggggggg
ggggggggggggggggggggg
ggggSSggggggggggggggg
ggggSSSgggggggggggggg
ggggSSSgggggggggggggg
ggggSSSgggggggggggggg
ggggggggggggggggggggg
ggggggggggggggggggggg
ggggggggggggggggggggg
fff1
cccc
fff2

View file

@ -1,19 +1,19 @@
ggggggfffffffffffffggggtgggcs
fffffhfffggfftgggrgrffffggggc
fffffhfffggfftgggrrrffffggggc
ffffffggghggghgrrgfgrrfffgggf
ffthgggffggggrrgggfftgrrrggff
fffgggfgfggghCgghhgggffgfrggf
fffgggffggtCC1gggggffffggrggf
ffthgggffggggmrgggfftgrrrggff
fffgggfgfggghCrghhgggffgfrggf
fffgggffggtCC1rggggffffggrggf
fffffgggggggCCCggfffffffggrgg
ccccftffffgghhgffffftffcccrgt
ccccccggffffggghggggfcccccrrg
ssssscgcfffggggfhfgcccsssscrg
ssssccctgfffggggggccssgtssccr
ccc//cggffffggghggggfcccccrrg
csssccgcfffggggfhfgcccsssscrg
ssssccptgfffggggggccssgtssccr
sssccgggffffffgggggcsssgssccr
sssschgggffhhmffggccssshssscr
sscccchhhtfmfhhhfgcccsstssscr
ccccgthmmmhhhmmfffcsssssssccr
tcggggghmmmtmmmhhggcccccsscrg
cccccchhhtfmfhhhfgcccsstssscr
c/gcgthmmmhhhmmfffccssssssccr
tcggggghmmmtmmmhhggcccccsscpg
ccsggggfffhhhmmmthgggcgcsccrt
gggtggfffhhmmmmhhfffggccccrhh
gggggfffhmmmhmmmmmfffgtcc//gf
@ -21,6 +21,6 @@ chhgggfffmhhhhmmhffffrc//cgtf
sccfgfffhhhmmmhhhhffgr/cccgff
ccgggggffggfhhfffffrrggccgggf
tggggfffgCgfghgrtrrggtgcggfff
gggffhhfCC2Chhrfrgggggcctggfh
gggffhhfCC2rhhrfrgggggcctggfh
ggtggftfhgCCrrrhhffccccsscghm
ggggffhhggggggggmmcccssssschm

View file

@ -1,41 +1,41 @@
ggggggffggggggggtDvcsssggggggggggggggggggggggggg
gggggfffffggggggRRRcsgcggggggggggggggggggggggggg
ggvggfggfffgggggRRR\cggggggggggggggggggggggggggg
ggggCCgggffggggcRc\Rggggggggtggggggtgggggggggggg
ggffC1Cggggggtcc|ccgRRgggggggggggtgggggggggggggg
gggfffCffggghhggccggRRgggggggggggggggggggggggggg
ggggfffffgghhggccggggRRggggggggCCCgggggggggggggg
ccggggggghhggccgggggggRtgggggggC3ggggggggggggggg
ccccgcchhgcccggggggggrrrggggggghCggggggggggggggg
gvccccctgccggggggggggggrrrgggggtgggggggggggfffff
ggggggcccggggvgggggggmggggrggggggggggggggggggggg
ggggggffggggggggtDvcsssddggggggggggggggggggggggg
gggggfffffggggggRRRcsdcdgggggggggggggggggggggggg
ggvggftgfffgggggRRR\cddggggggggggggggggggggggggg
ggggCCgggffggggccc\Rggggggggtggggggggggggggggggg
ggffC1CggggggtcccccgRRgggggggggggtgggggggggggggg
gggfffCffggghhggccggRRgggggggggggggggCgggggggggg
ddggfffffgghhgg\cggggRRgggggggggggggg2CCCggggggg
ccdgggggghhggccgggggggRtgggggggggggggCCCgggggggg
ccccgcchhdcccggggggggrrrggggggghgggggggmgggggggg
dvcc|cctgccggggggggggggrrrgggggtggggghghgggfffff
ddddggc|cggggvgggggggmggggrggggggggggghhgggggggg
gggggggggggggggggggmhhhgggrggggggggggggggggggggg
ggggggvgggggggggghghhfgffgrrgvgggggggggggggggggg
gggggggggggggggggggffffffhgrggggggtggggggggggggg
gggggggggggggggggffffhfghhmrfggggggggggggggggggg
gggggggtgggggggggffhfffghgggrrgggggggggggggggggg
gggggggggggggggggffhfffghgggrrgggggggggggggggggg
ggggggggggggggggggfffffvggggvgrrgggvgggggggggggg
ggtgggggggggggggggggfggggggggggrgggggggggggggggg
gggggggggggggggggggggggggggggggrggggggCggggggggg
ggggggggggDggtgggggggggggggggggrgggggCCCgggggggg
ggggggggggggmumugggggggggggggrrvgggggC2ggggggggg
gggggggggggguuuuuugggggggggrrgggggggggCCgggggggg
ggggggggggmguuDumuugmggggrrggggggggggggggggggggg
gggtggggggmmmuuuumummrrrrggggtgggggggggggggggggg
ggggggggggguuuugmggrrgggggggggggggggggggggghfggg
gmggggggDgggggDgggggggggDcccggggggggvgggggfghggg
hhfhhggggggggggggggggggggggcc/ggtgggggggggfhfhff
tmmgggggggggghmmgfmggggtggggcgccccggggggtggtffgf
hhghhgggggggggfghfgmgfgggggggggcscccggggggffhggg
ggtgggggggggggggggggfggcccgggggrgggggggggggggggg
gmghggggggggggggggggcccsscgggggrggggggCggggggggg
gmmhmhgmmgDhgtggggggccsscggggggrgggggCCCgggggggg
gmhmmmhhhhghmumuggggccsccggggrrvgggggC3ggggggggg
gcmmmhhmhgghuuuuuuggggcgccgrrgggggggggCCgggggggg
cggghghmmgmDuuDumuugmgggg/rggggggggggggggggggggg
pvgtggmgghmmmuuuumummrrrrcgggtgggggggggggggggggg
ccggggmghhhuuuugmggrrggggcggggggggggggggggghfggg
cmggggghDmhgggggggggggggDcccggggggggvgggggfghggg
hhfhhghmmmgmgggggggggggggggcc|ggtgggggggggfhfhff
tmmggmmmmgmmghmmgfmggggtggggcgccccggggggtggtffgf
hhghhgmgggmgggfghfgmgfgggggggggcscccggggggffhggg
ggggggggggggggggfgggtggggggggggcsscccgggggfghgfg
ggggggtgggggggggmggggggggggggtgccsscgggggggggggg
ggggggggggCCgtggggggggggggggggggcccggggggggggggg
gggggggggm4CCggggggggggggggggggggggggggggggggggg
ggggggggggCggggggggggggtggggggggggggggggtggggggg
gggggggggggggggggggggggggggggghgffffgggggggggggg
ggggggtggggggggggggggggggggghgffffgghggggggggggg
ggggggggggggggggggggggggggggfffmffffghhgggggtggg
ggggggggggggggtgggggggggggffffghfggffmfffggggggg
ggggggggggggggggggggggggggggfhfggthggggtgggggggg
ggggggggggggggggggggggggggfffghhggggggggggtggggg
gggggggggggggggggggggggggggggggggggtgggggggggggg
ggggggtgggggggggmggggggggggggtgccssccdgdgdgdddgg
ggggggggggCCggggggggggggggggggggcccccdggggddddgg
gggggggggm4CCgggggggggggggggggggggddcdddggggdddd
ggggggggggCggggggggggggggggdgddgggddcddgtggddggg
gggggggggggggggggggggggggdgddgdgfffddddggdggdgdd
ggggggtggggggggggggdddgddgdgdgddddggdgdgdgdgggdd
ggggggggggggggggggddddgdgdggfffmffdfghhggddddggg
ggggggggggggggggdgdddddddgffffghfggdfmfffdggdddg
ggggggggggggggggggddgdddggddfhfgdthdggggggdddddd
ggggggggggggggggggggggggggdffghhggggdggdgggddddg
ggggggggggggggggggggggggggggdgdgggdcgggggggddggg

View file

@ -1,50 +0,0 @@
ccgggggggggggccSSSfftSSSgggggggtgggggcccggggtfftgg
ccgggggggggggccSSfSffSSgggtggggggggggcccgggfffffgg
cgggggggggggccccfgSSSgggggggggggggggcggcgggfcfffff
ccggggggtgggggcfggggggggggggggtggggtccgcccggcctfff
ccccggggggggggCCCggggggggggtgggggggcccccccccgggfff
ccctcgggggggggC2Cfggggggggggggggggmmcccccccggggfff
ccccccgcggggggCCCffgggtggggggggggmmmmmcctccgggggff
ccccccgcctgfgggtgfftggggggggggggmmmmmmmmccggggggff
ccccccggccffggggffffccggggggtggggmmmmmmccgggggffff
cccggcgggccfffgffffffcggggggggggggmgmmmmggggggffff
cccgccccgfffffffffffgtgdgtggggggggggmmgggggmgtffff
ccccddcgffffffffffffgSgddggggggggggggmmgggtmmfffff
cccddddddfffffffffffSSgddcgmmgtgggggggmmggmmfffftf
ccdddftdddfffggggfftggdddccmmgcggggggtggggmfmffffg
ccdddfffftfffgggggcggddddcctmcccggggggggdgmmffffgg
cdtddfffffffcgggggccggdddcmmmccccgggggggdddmffmmgg
dgggggfffddccgggccccgdggccmmmmmmmmmggggddddtffmmgg
ddggggffddtgcggccccctgggcccmmmmmgmmgggdddddddggmmg
ddggggffgggggggcccccfgggccccmmmmgtmmdddddddgggggmm
gdgdggtfgffggfffcccffffggcccmmmmmmmmddddddggggggmg
ggdgdggffffgggftffffffffggctmmmmmggmmdddgggggggggg
gggdgggfffffggfccfffffffgggmmmmtmgggdddggggggggggg
ggdggggfffffgfffcffffdffggccmmmmmggdddddgggggggggg
gdgggggffffffgtfffftgddggcccmmmgmddddmmddggggggggg
ddggcccfffffffgfgggggggdgccccctggdddddmggggggggggg
tdggccccggfffgfggdggggdggcgtccgggggmmmmggggggggggg
ddccccccggffffgggdddddggggggcgggggggmmmggggggggggg
gcgcggcggggggfgggdgdddggggggggggggggmmgddggggggggg
ggtggggggggtgggggggdgggggggggggggggggmdggdgggggggg
ccccggcggggggggggggggggggggggggggmmmdddgdddggggggg
cccccccgggggggggggggggggggggggggggmmdddggddddddggg
cccccgcggggggtgggtggggggggggggggtgmmdddggggddddggg
cccccggcgggggggggggggggmgmgggtgggmgddddggggtmddgtg
cccccgcccggggggggggggggmtmmmgggggggdddddgmmmmmdggg
ccgggccgcggggggggggggggmmmmmggggggggddddhhmmmmmmgh
tcggggggggggggggggtgggmmmmmmmgggggggdddhhhmmmmmmhh
ccggggtgggggggggggggggggmmmmmmggtggddthhhmmmmmmmhg
ggggggggggtggggggggggggmmmmmmggggggggghhhhmgmmghgg
ggggggggggggggggggggggmmmtmmmggggggggghhSmgmgmgghh
fffgggggggggggggtgggggmmmmmmmmgggggggggSCCCgmmghhh
fffgCCChgggffgggggggggmmmmgmmgggggggggggC1Cmgmhhhh
ffggC3ChhhgffgggggggggmmmgtggggggggtggggCCCtghhhhh
fffhCCChhhhftggggtgggggmgggggggggggggggggSgghhhhhh
tffhhhhhhhhhffggggggggggmmmggggtggggggggggghhhhShh
fffhhhhhgghffggggggghggtgmmmggggggggggggggghhthSSS
fffhhhhggggftgggggghhhggmmmmggggggggggggggghhhggSg
ffffhhhgggggfgggghhhggggmmmmgggggggggggggghghhgggg
fffffgggggffgggghhhhhghhmggmgmmgggggggggggghghgggg
ffffffgggfffgggghhhhhhhhggggmmmgggggggggggghhggggg
ffffffffffffgggghhhhhhhggggggmmgggggggggggghgggggg

View file

@ -143,8 +143,9 @@ Defeat:
description=Gwiti Ha'atel
message="Die, yes die, and go to the Land of the Dead. Perhaps one day you will be back under my command!"
[/message]
[endlevel]
[endlevel]
result=victory
bonus=yes
[/endlevel]
[/event]
@ -200,6 +201,20 @@ Defeat:
[/message]
[/event]
[event]
name=turn 9
[message]
id=msg2_1_16
description=Nati Ha'atel
message="You miserable wretch, know that it is only by my mercy that you look upon the sun again, for you shall die before it sets again."
[/message]
[message]
id=msg2_1_17
description=Gwiti Ha'atel
message="May I remind you that even as we speak, my undead legions are marching towards you?"
[/message]
[/event]
[/scenario]

View file

@ -88,7 +88,7 @@ Defeat
[message]
id=msgcrossroads4
description=Kalenz
message="Beware! These forests are not safe! Asheviere has hired Orcs to guard these roads, because of their strategic important. We shall have to fight to get by here."
message="Beware! These forests are not safe! Asheviere has hired Orcs to guard these roads, because of their strategic importance. We shall have to fight to get by here."
[/message]
[message]
id=msgcrossroads5
@ -127,7 +127,7 @@ Defeat
[/unit]
[message]
id=msgcrossroads1
description=Nioden
description=Niodien
message="Stay on the path! The forests here are not safe!"
[/message]
[/event]

View file

@ -2,7 +2,7 @@
name="The Isle of Anduin"
map=map1
music=wesnoth-4.ogg
music=wesnoth-8.ogg
{DAWN}
{MORNING}

View file

@ -0,0 +1,224 @@
[scenario]
name="Mages and Elves"
id="Mages_And_Elves"
map=undmap3
turns=40
{DUSK}
{FIRST_WATCH}
{SECOND_WATCH}
{DAWN}
{MORNING}
{AFTERNOON}
next_scenario="Crelanus_Book"
music="wesnoth-2.ogg"
objectives="
Victory:
@Move Gwiti to the Tower of Sorcery
@Kill both enemy leaders
Defeat:
#Death of Gwiti Ha'atel
#Turns run out"
[side]
description=Gwiti Ha'atel
type=Dark Apprentice
side=1
canrecruit=1
controller=human
recruit= Dark Adept,Ghost,Walking Corpse,Vampire Bat,Skeleton,Skeleton Archer
enemy=2,3
[/side]
[side]
type=Great Mage
description=Quirind
side=2
canrecruit=1
#ifdef HARD
recruit= Great Mage,Arch Mage,Red Mage,White Mage,Paladin
#ifdef NORMAL
recruit= Arch Mage,Red Mage,White Mage,Mage,Knight,Heavy Infantry
#endif
#ifdef EASY
recruit= Red Mage,Mage,Horseman,Heavy Infantry
#endif
#ifdef EASY
gold=40
#endif
#ifdef NORMAL
gold=65
#endif
#ifdef HARD
gold=90
#endif
enemy=1
[/side]
[side]
type=Elvish Marshal
description=Lessalin
side=3
canrecruit=1
#ifdef HARD
recruit= Elvish Hero,Elvish Ranger,Elvish Captain,Elvish Outrider,Gryphon Rider,Elvish Scout,Elvish Druid
#ifdef NORMAL
recruit= Elvish Hero,Elvish Fighter,Gryphon Rider,Elvish Archer,Thief,Elvish Scout,Elvish Shaman
#endif
#ifdef EASY
recruit= Elvish Fighter,Elvish Archer,Elvish Scout,Thief,Elvish Shaman
#endif
#ifdef EASY
gold=60
#endif
#ifdef NORMAL
gold=90
#endif
#ifdef HARD
gold=120
#endif
enemy=1
[/side]
[event]
name=start
[message]
id=msg2_3_1
speaker=narrator
message="After sending the Dark Spirit away for his failure, Gwiti turned towards the Tower of Kaleon, where the greatest mages once studied."
[/message]
[message]
id=msg2_3_2
description=Gwiti Ha'atel
message="At last, I have reached the main road. Unless I am far off my course, I should find the Tower of Kaleon here, filled with the secrets of ancient mages. Soon they shall all be mine."
[/message]
[message]
id=msg2_3_3
description=Quirind
message="A necromancer! I must send for aid."
[/message]
[message]
id=msg2_3_4
description=Quirind
message="Accursed and dreadful one, know that we mages, guardians of the Tower of Kaleon, shall bar your way with all our spells! Flee now and you may survive."
[/message]
[message]
id=msg2_3_5
description=Lessalin
message="Quirind, know that you have the Elves at your back."
[/message]
[message]
id=msg2_3_6
description=Lessalin
message="Foul sorcerer of death, go far from this place or we shall send you to your own realm."
[/message]
[message]
id=msg2_3_7
description=Gwiti Ha'atel
message="Not born is the one that could challenge me!"
[/message]
[/event]
[item]
x=15
y=3
image=terrain/dwarven-doors.png
[/item]
[event]
name=die
[filter]
description=Gwiti Ha'atel
[/filter]
[message]
id=msg2_3_8
speaker=unit
message="No! No! Noooo! It is over, I feel the shades reaching for me..."
[/message]
[endlevel]
result=defeat
[/endlevel]
[/event]
[event]
name=die
[filter]
description=Quirind
[/filter]
[message]
id=msg2_3_9
speaker=unit
message="Argh! I have fallen, and the Tower lies stripped of its defenses!"
[/message]
[/event]
[event]
name=die
[filter]
description=Lessalin
[/filter]
[message]
id=msg2_3_10
speaker=unit
message="Quirind, we have failed! You must guard the tower."
[/message]
[/event]
[event]
name=time out
[message]
id=msg2_3_11
description=Quirind
message="Ah ha ha ha! The tower's protective spells are now in force, you cannot enter without mastering a magic equal to it."
[/message]
[/event]
[event]
name=moveto
[filter]
x=15
y=3
description=Gwiti Ha'atel
[/filter]
[message]
id=msg2_3_12
speaker=unit
message="Haha! I have gained entry to the tower!"
[/message]
[message]
id=msg2_3_13
description=Lessalin
message="A curse upon that foul necromancer!"
[/message]
[endlevel]
result=victory
bonus=yes
[/endlevel]
[/event]
[/scenario]

View file

@ -117,7 +117,7 @@ Defeat:
[message]
id=msg6_4b
description=Li'sar
message=Don't tell me such treason. Your lies will perish with you!
message=Treason! Your lies will perish with you!
[/message]
[message]
id=msg6_5

View file

@ -1,6 +1,6 @@
[multiplayer]
name=Random map
map_data="{ranmap.cfg}"
map_generation=default
turns=90
id=ranmap
@ -23,10 +23,4 @@
canrecruit=1
controller=human
[/side]
[side]
side=3
enemy=1
canrecruit=1
controller=human
[/side]
[/multiplayer]

View file

@ -203,9 +203,9 @@ Defeat:
name=have_thieves
value=yes
[/set_variable]
[can_recruit]
[allow_recruit]
type=Thief
[/can_recruit]
[/allow_recruit]
[/command]
[/option]
[option]

View file

@ -1,415 +0,0 @@
[scenario]
name="The Liberation Front"
map=LiberationMap
turns=28
{DAWN}
{MORNING}
{AFTERNOON}
{DUSK}
{FIRST_WATCH}
{SECOND_WATCH}
id=The_Liberation_Front
next_scenario=Undefined
music="wesnoth-4.ogg"
[bigmap]
image=misc/map.png
[dot]
type=cross
x=187
y=187
[/dot]
[/bigmap]
objectives="
Victory:
@Defeat All three Orc Leaders
Defeat:
#Death of Konrad
#Death of Delfador
#Death of Kalenz
#Death of Li'sar
#Time runs out"
[item]
x=14
y=3
image=terrain/dwarven-doors.png
[/item]
[item]
x=10
y=26
image=terrain/castle-ruins.png
[/item]
[item]
x=10
y=27
image=terrain/castle-ruins.png
[/item]
[item]
x=11
y=27
image=terrain/castle-ruins.png
[/item]
[item]
x=17
y=21
image=terrain/castle-ruins.png
[/item]
[item]
x=5
y=34
image=terrain/castle-ruins.png
[/item]
[side]
type=Commander
description=Konrad
side=1
canrecruit=1
controller=human
recruit=Elvish Scout,Elvish Fighter,Elvish Archer,Horseman,Mage,Elvish Shaman,Merman,Thief,Gryphon Rider, Dwarf,
enemy=2,3,4
[/side]
[side]
type=Orcish Warlord
description=Knafa-Telfar
side=2
canrecruit=1
recruit=Orcish Warrior,Wolf Rider,Orcish Crossbow,Orcish Assassin,Troll Warrior
#ifdef EASY
gold=250
#endif
#ifdef NORMAL
gold=300
#endif
#ifdef HARD
gold=350
#endif
enemy=1
[/side]
[side]
type=Orcish Warlord
description=Urug-Tan
side=3
canrecruit=1
#ifdef EASY
recruit=Orcish Grunt,Wolf Rider,Orcish Archer,Orcish Assassin,Troll
gold=250
#endif
#ifdef NORMAL
recruit=Orcish Grunt,Goblin Knight,Orcish Crossbow,Orcish Assassin,Troll Warrior
gold=300
#endif
#ifdef HARD
recruit=Orcish Warrior,Goblin Knight,Orcish Crossbow,Orcish Assassin,Troll Warrior
gold=350
#endif
enemy=1
[/side]
[side]
race=Orcs3
type=Orcish Warlord
description=Shuuga-Mool
side=4
canrecruit=1
recruit=Orcish Warrior,Wolf Rider,Orcish Crossbow,Troll Warrior,Orcish Slayer
#ifdef EASY
gold=250
#endif
#ifdef NORMAL
gold=300
#endif
#ifdef HARD
gold=350
#endif
enemy=1
[/side]
[side]
race=Orcs3
type=Orcish Warlord
description=Ba-grah'Nook
side=5
canrecruit=0
[/side]
[event]
name=start
[recall]
description=Delfador
[/recall]
[recall]
description=Kalenz
[/recall]
[recall]
description=Li'sar
[/recall]
#move The orcs off their keeps so they don't recruit yet
[command]
[kill]
description=Knafa-Telfar
[/kill]
[/command]
[command]
[unit]
side=2
x=29
y=22
description=Knafa-Telfar
type=Orcish Warlord
canrecruit=1
[/unit]
[/command]
[command]
[kill]
description=Urug-Tan
[/kill]
[/command]
[command]
[unit]
side=2
x=1
y=35
description=Urug-Tan
type=Orcish Warlord
canrecruit=1
[/unit]
[/command]
[/event]
[event]
name=turn 1
[message]
description=Konrad
id=msg13_1
message="Alright Delfador, now that I have claimed the Scepter of Fire I am going to hold you to your promise."
[/message]
[message]
description=Delfador
id=msg13_2
message="Which one?"
[/message]
[message]
description=Konrad
id=13_3
message="That we free these lands from the scourge of the orcs!"
[/message]
[message]
description=Delfador
id=msg13_4
message="Very well Konrad. But the orcs must have contacted Asheviere about our trip into the mines, and I doubt she will trust them to take care of the job. So make haste, and dispatch these beasts quickly, lest reinforcements arrive."
[/message]
[message]
description=Shuuga-Mool
message="The human and his friends have returned! I will deal with them myself!"
id=msg13_5
[/message]
[message]
speaker=Knafa-Telfar
id=msg13_6
message="If your sure boss..."
[/message]
[message]
description=Shuuga-Mool
id=msg13_7
message="COURSE I'm sure worm! Do as your told!"
[/message]
[message]
speaker=Knafa-Telfar
id=msg13_8
message="Alright, alright! Sorry boss!"
[/message]
[/event]
[event]
name=die
[filter]
description=Shuuga-Mool
[/filter]
[message]
id=msg13_9
description=Knafa-Telfar
message="They killed the boss!"
[/message]
[message]
id=msg13_10
description=Urug-Tan
message="I knew you should've helped him!"
[/message]
[message]
id=msg13_11
description=Knafa-Telfar
message="So this is my fault!?! Nevermind! Let's just kill them!"
[/message]
[command]
[kill]
description=Knafa-Telfar
[/kill]
[/command]
[command]
[unit]
side=2
x=29
y=21
description=Knafa-Telfar
type=Orcish Warlord
canrecruit=1
[/unit]
[/command]
[command]
[kill]
description=Urug-Tan
[/kill]
[/command]
[command]
[unit]
side=2
x=1
y=35
description=Urug-Tan
type=Orcish Warlord
canrecruit=1
[/unit]
[/command]
[/event]
[event]
name=moveto
[filter]
x=27-29
y=19-23
[/filter]
[command]
[kill]
description=Knafa-Telfar
[/kill]
[/command]
[command]
[unit]
side=2
x=29
y=21
description=Knafa-Telfar
type=Orcish Warlord
canrecruit=1
[/unit]
[/command]
[message]
description=Knafa-Telfar
id=msg13_15
message="They're attacking me boss! I gotta defend myself!"
[/message]
[/event]
[event]
name=moveto
[filter]
x=1-3
y=33-37
[/filter]
[command]
[kill]
description=Urug-Tan
[/kill]
[/command]
[command]
[unit]
side=2
x=29
y=21
description=Urug-Tan
type=Orcish Warlord
canrecruit=1
[/unit]
[/command]
[message]
description=Urug-Tan
id=msg13_16
message="They're attacking me boss! I gotta defend myself!"
[/message]
[/event]
[event]
name=turn 18
[unit]
description=Ba-grah'Nook
type=Orcish Warlord
canrecruit=0
x=20
y=44
side=5
[/unit]
[unit]
description=Grungy
type=Troll Warrior
x=20
y=45
side=5
[/unit]
[unit]
description=Stupid
type=Troll
x=19
y=45
side=5
[/unit]
[unit]
description=Ugly
type=Troll
x=21
y=45
side=5
[/unit]
[unit]
description=Gorba
type=Orcish Slayer
x=19
y=44
side=5
[/unit]
[unit]
description=Bogar
type=Orcish Slayer
x=21
y=44
side=5
[/unit]
[message]
description=Ba-grah'Nook
id=msg13_12
message="Hail! We've come in response to your message, the Queen has given us specific orders to help you deal with these humans once and for all. We're the vanguard that's been sent out from an entire army that's been ordered to deal with these miscreants!"
[/message]
[message]
description=Delfador
id=msg13_13
message="This is a bad turn of events! We must finish them quickly and flee! We are not capable of dealing with an entire army dedicated to wiping us out in our current condition!"
[/message]
[/event]
[event]
name=die
[filter]
description=Knafa-Telfar
description=Urug-Tan
[/filter]
[message]
description=Delfador
id=msg13_14
message="We've slain our opposition! Now let us make haste!"
[/message]
[endlevel]
result=victory
bonus=yes
[/endlevel]
[/event]
{deaths.cfg}
[/scenario]

View file

@ -12,7 +12,7 @@
{DAWN}
id="Skull_Agarash"
next_scenario=null
next_scenario="Mages_And_Elves"
music="wesnoth-3.ogg"
@ -58,13 +58,13 @@ Defeat:
canrecruit=1
recruit=Orcish Grunt,Wolf Rider,Orcish Archer,Troll Whelp
#ifdef HARD
gold=180
gold=135
#endif
#ifdef MEDIUM
gold=120
gold=90
#endif
#ifdef EASY
gold=80
gold=60
#endif
enemy=1,4
[/side]
@ -78,13 +78,13 @@ Defeat:
canrecruit=1
recruit=Orcish Grunt,Wolf Rider,Orcish Archer,Troll Whelp
#ifdef HARD
gold=180
gold=135
#endif
#ifdef MEDIUM
gold=120
gold=90
#endif
#ifdef EASY
gold=80
gold=60
#endif
enemy=1,3
[/side]
@ -96,15 +96,15 @@ Defeat:
[message]
id=und2_2_1
speaker=narrator
message="After Gwiti destroyed his brother, he was planning a march upon Wesnoth. But a Dark Spirit came to him, counselling him..."
message="After Gwiti destroyed his brother, a Dark Spirit came to him, counselling him..."
[/message]
[/command]
[command]
[move_unit_fake]
type=Wraith
x=1,2,3,4,5,6,7
y=4,4,4,4,4,4,4
x=1,2,3,4,5,6,7,7
y=4,4,4,4,4,4,4,5
[/move_unit_fake]
[/command]
@ -122,7 +122,7 @@ Defeat:
[message]
id=und2_2_2
description=Dark Spirit
message="Gwiti... Gwiti!"
message="Gwitiii... Gwiti!"
[/message]
[message]
id=und2_2_3
@ -132,7 +132,7 @@ Defeat:
[message]
id=und2_2_4
description=Dark Spirit
message="Gwiti, do not yet march upon Wesnoth. First, you shall go south, against the orcs, and there find the Skull of Agarash."
message="Gwiti, do not yet march in pursuit of your war. First, you shall go south, against the orcs, and there find the Skull of Agarash."
[/message]
[message]
id=und2_2_5
@ -184,8 +184,9 @@ Defeat:
description=Gwiti Ha'atel
message="Argh! This is only half of the skull!"
[/message]
[endlevel]
result=victory
[endlevel]
result=victory
bonus=yes
[/endlevel]
[/event]

View file

@ -3,6 +3,8 @@ image=ocean
name=deep water
char=s
blue=150
submerge=0.5
unit_height_adjust=-3
[/terrain]
[terrain]
@ -10,12 +12,16 @@ image=coast
name=shallow water
char=c
blue=250
submerge=0.4
unit_height_adjust=-4
[/terrain]
[terrain]
image=swampwater,swampwater2,swampwater3
name=swamp water
char=w
submerge=0.4
unit_height_adjust=-3
[/terrain]
[terrain]
@ -168,6 +174,15 @@ char=C
red=100
green=100
blue=100
unit_height_adjust=3
[/terrain]
[terrain]
image=keep
name=keep
char=K
unit_height_adjust=8
aliasof=C
[/terrain]
[terrain]

164
data/terrain_generator.cfg Normal file
View file

@ -0,0 +1,164 @@
[map_generator]
name=default
width=40
height=40
iterations=1000
hill_size=10
max_lakes=40
villages=300
players=2
min_lake_height=500
lake_size=150
river_frequency=20
temperature_iterations=40
temperature_size=50
default_flatland=g
roads=3
road_windiness=3
#list of common terrain types which come in at
#different heights, from highest to lowest
[height]
height=700
terrain=m
[/height]
[height]
height=600
terrain=h
[/height]
[height]
height=40
terrain=g
[/height]
[height]
height=30
terrain=d
[/height]
[height]
height=5
terrain=c
[/height]
[height]
height=0
terrain=s
[/height]
#at low temperatures, and at reasonable height,
#snow appears
[flatland]
max_temperature=200
min_height=400
terrain=S
[/flatland]
#swamp appears on low land, at moderate temperatures
[flatland]
min_temperature=500
max_temperature=700
max_height=200
terrain=w
[/flatland]
#forest appears at moderate temperatures
[flatland]
min_temperature=300
max_temperature=600
terrain=f
[/flatland]
#desert appears at high temperatures
[flatland]
min_temperature=900
terrain=d
[/flatland]
#road costs
[road_cost]
terrain=g
cost=1
convert_to=r
[/road_cost]
[road_cost]
terrain=d
cost=2
convert_to=r
[/road_cost]
[road_cost]
terrain=f
cost=3
convert_to=r
[/road_cost]
[road_cost]
terrain=c
cost=5
convert_to_bridge=|,/,\
[/road_cost]
[road_cost]
terrain=h
cost=5
convert_to=r
[/road_cost]
[road_cost]
terrain=m
cost=10
convert_to=r
[/road_cost]
[road_cost]
terrain=r
cost=0
convert_to=r
[/road_cost]
#road going through snow is covered over by
#the snow (presumably the road was built when
#it wasn't snowing)
[road_cost]
terrain=S
cost=2
convert_to=S
[/road_cost]
[village]
terrain=g
convert_to=v
[/village]
[village]
terrain=d
convert_to=v
[/village]
#villages in forest are Elvish
[village]
terrain=f
convert_to=t
[/village]
[village]
terrain=h
convert_to=v
[/village]
[village]
terrain=m
convert_to=v
[/village]
#villages in snow
[village]
terrain=S
convert_to=V
[/village]
[castle]
valid_terrain=g,f,h
min_distance=16
[/castle]
[/map_generator]

View file

@ -1,42 +1,41 @@
[language]
language="Nederlands"
id=nl #language code - English=en, French=fr, etc
13_3="That we free these lands from the scourge of the orcs!"
A_Choice_Must_Be_Made="A Choice Must Be Made"
A_Choice_Must_Be_Made="Staan voor een keuze"
A_Choice_Must_Be_Made_objectives="
Victory:
@Defeat either of the enemy leaders
Defeat
Overwinning:
@Versla een van de leiders
Verslagen:
#Dood van Konrad
#Dood van Delfador"
AncientLich="Ancient Lich"
AncientLich_description="The final form that a mage of the undead can achieve, the Ancient Lich strikes terror into the hearts of those who see him. Not only is his touch that of death, but his spells are powerful enough to freeze even the bravest where they stand."
ArchMage="Arch Mage"
ArchMage_description="A leader among the mages, the arch mage hurls huge balls of fire at his enemies. The arch mage can teleport from any village to any other friendly village, translating himself from place to place in an instant."
Assassin="Assassin"
Assassin_description="Assassins are masters of the night. Like rogues they can backstab, and ignore enemy zones of control. They can also throw poison-tipped knives at their enemies from long range."
Blackwater_Port="Blackwater Port"
AncientLich="Oude Lich"
AncientLich_description="Het hoogste wat een magiër van de ondoden kan bereiken. De Oude Lich brengt een koude angst in de harten van die die hem zien. Niet alleen is zijn aanraking er een van dood, zijn spreuken zijn krachtig genoeg om zelfs de dapperste mannen aan de grond te nagelen."
ArchMage="Oppermagiër"
ArchMage_description="De Oppermagiër is een leider onder de magiërs. Hij kan enorme vuurballen naar de vijand gooien. De Oppermagiër kan zichzelf teleporteren van elk dorp naar elk andere bevriende dorp, zich zelf in een ogenblik van plaats naar plaats bewegend."
Assassin="Sluipmoordenaar"
Assassin_description="Sluipmoordenaars zijn de meesters van de nacht. Net als rogues beheersen ze de ruggesteek en worden ze niet tegengehouden door vijandige zones. Sluipmoordenaars gooien messen met een giftige punt van een grote afstand op hun vijand."
Blackwater_Port="Zwartwater Haven"
Blackwater_Port_objectives="
Victory:
@Defeat enemy leader
@Resist until the end of the turns
Defeat:
Overwinning:
@Versla vijandige leider
@Houdt stand tot de laatste beurt
Verslagen:
#Dood van Konrad
#Dood van Delfador
#Dood van Seimus"
BloodBat="Blood Bat"
BloodBat_description="The fur of this undead flying beast is tainted red by the blood of its victims. The Blood Bat is fast, and can drain the blood of those it attacks, thus healing itself. Through its draining, it can even end up stronger than it began the battle!"
BoneShooter="Bone Shooter"
BoneShooter_description="These undead elite archers use the bones of those slain in battle not only to kill their foes, but also to strike terror in their hearts."
Brother_Against_Brother="Brother Against Brother"
BloodBat="Bloedvleermuis"
BloodBat_description="De vacht van dit ondode vliegende beest zit onder het rode bloed van zijn slachtoffers. De Bloedvleermuis is snel en kan het bloed opzuigen van degene die het aanvalt en zichzelf daarmee genezen. Het kan er zelfs sterker dan aan het begin van de strijd door worden!"
BoneShooter="Beender Schieter"
BoneShooter_description="Deze ondode elite boogschutters gebruiken de botten van zij die vielen als pijlen. Niet alleen dood zoiets, maar slaat de angst ook om het hart."
Brother_Against_Brother="Broer tegen broer"
Brother_Against_Brother_objectives="
Victory:
@Defeat your brother Nati Ha'atel
Defeat:
Overwinning:
@Versla je broer Nati Ha'atel
Verslagen:
#Dood van Gwiti Ha'atel
#Turns run out"
#Geen beurten meer"
Cavalry="Cavelarie"
Cavalry_description="The best riders in Wesnoth are recruited into the military to become members of the cavalry. This strictly disciplined force is especially suited to capturing and holding villages."
Cavalry_description="De beste rijders in Wesnoth worden gerecruteerd voor het leger om bij de cavalerie te komen. Deze gedisciplineerde eenheid is vooral geschikt voor de verovering en het vasthouden van dorpen."
Chocobone="Chocobone"
Chocobone_description="Riding the bones of large birds used as mounts by an ancient and lost civilization, the skeletons can move faster than most calvary units."
Commander="Commander"
@ -141,9 +140,9 @@ swiftly fly towards their victims."
GryphonRider_description="Only a few of the already nature-loving elves are able to make a friendship bond with the mighty gryphons. Those who do can ride these flying beasts, discovering the whole new world of the skies."
Gryphon_Mountain="Gryphon Mountain"
Gryphon_Mountain_objectives="
Victory:
@Defeat the mother gryphon and the enemy commander
Defeat:
Overwinning:
@Versla the mother gryphon and the enemy commander
Verslagen:
#Dood van Konrad
#Dood van Delfador
#Dood van Kalenz"
@ -153,9 +152,9 @@ Defeat:
Halbardier_description="The best among the soldiers are choosen to become halberdiers. Thought a little slower then the sword, their weapon can strike deadly blows."
Hasty_Alliance="Hasty Alliance"
Hasty_Alliance_objectives="
Victory:
@Defeat enemy leader
Defeat:
Overwinning:
@Versla vijandige leider
Verslagen:
#Dood van Konrad
#Dood van Delfador
#Dood van Kalenz
@ -183,23 +182,23 @@ For this reason, the mage is an excellent choice for flushing out enemies hiding
When a unit is adjacent to a mage of Light, it will fight as if it were day when it is dusk, and as if it were dusk when it is night. Like the White Mage, the Mage of Light also cures adjacent friendly units."
Merman="Merman"
MermanLord="Merman Lord"
MermanLord_description="The Merman Lord is a master of the sea, skilled in use of the trident, the Merman Lord easily defeats any enemy who is foolish enough to wander into his preferred environment."
MermanLord_description="The Merman Lord is a master of the sea, skilled in use of the trident, the Merman Lord easily Verslagens any enemy who is foolish enough to wander into his preferred environment."
Merman_description="A skilled creature of the sea, the Merman is powerful and quick in any amphibious environment, but struggles on land."
Mountain_Pass="Mountain Pass"
Mountain_Pass_objectives="
Victory:
Overwinning:
@Move Konrad to the end of the road
Defeat:
Verslagen:
#Dood van Konrad
#Dood van Delfador
#Dood van Kalenz"
Muff_Malals_Peninsula="Muff Malal's Peninsula"
Muff_Malals_Peninsula_objectives="
Victory:
@Defeat Muff Malal
Defeat:
Overwinning:
@Versla Muff Malal
Verslagen:
#Dood van Konrad
#Turns run out"
#Geen beurten meer"
NORMAL="Held (normaal)"
Naga="Naga"
Naga_description="The naga, like the merman, are inhabitants of the seas. While they are smaller and nimbler than their counterparts, they share their distaste for dry land."
@ -207,13 +206,13 @@ Defeat:
Necromancer_description="A necromancer is a mage that decided to follow the paths of the dark arts. By tapping into the power of the undead, the necromancer can cast spells that drain the lifeforce from his foes and add it to his own."
Northern_Winter="Northern Winter"
Northern_Winter_objectives="
Victory:
@Defeat enemy leaders
Defeat:
Overwinning:
@Versla vijandige leiders
Verslagen:
#Dood van Konrad
#Dood van Delfador
#Dood van Kalenz
#Turns run out"
#Geen beurten meer"
Ogre="Ogre"
Ogre_description="Ogres are giant, stupid humanoids that usually live alone in the wilderness. While they can be easily outran or outsmarted, their strenght is not to be underestimated."
OrcishArcher="Orcish Archer"
@ -236,9 +235,9 @@ Defeat:
Pikeman_description="Pikemen are are more experienced soldiers that change their spears for long pikes. Pikemen can be deadly when fighting calvary."
Plunging_into_the_Darkness="Plunging into the Darkness"
Plunging_into_the_Darkness_objectives="
Victory:
Overwinning:
@Find the Dwarves
Defeat
Verslagen
#Dood van Konrad
#Dood van Delfador
#Dood van Kalenz"
@ -254,9 +253,9 @@ Defeat
RoyalGuard_description="Members of the Royal Guard are hand picked from the strongest and sturdiest of the army. They are deployed only in critical situations and, so far, they have always succeeded in the job at hand."
Sceptre="The Sceptre of Fire"
Sceptre_objectives="
Victory:
Overwinning:
@Capture the Sceptre of Fire with Konrad or Li'sar
Defeat:
Verslagen:
#Dood van Konrad
#Dood van Delfador
#Dood van Kalenz
@ -277,18 +276,18 @@ Defeat:
Skeleton_description="A warrior, slain in battle and brought back by dark magics. All undead are weak to fire and holy spells, but resistant against bladed weapons."
Skull_Agarash="The Skull of Agarash"
Skull_Agarash_objectives="
Victory:
Overwinning:
@Take the Skull of Agarash
Defeat:
Verslagen:
#Dood van Gwiti Ha'atel
#Turns run out"
#Geen beurten meer"
SleepingGryphon="Sleeping Gryphon"
SleepingGryphon_description="Shhhh! The gryphon is sleeping! You'd better not wake it up!"
Snow_Plains="Snow Plains"
Snow_Plains_objectives="
Victory:
@Defeat enemy leader
Defeat
Overwinning:
@Versla vijandige leider
Verslagen
#Dood van Konrad
#Dood van Delfador"
Soldier="Soldier"
@ -297,57 +296,57 @@ Defeat
Spearman_description="The spearman is the base of the human armies. These young soldiers are given basic training and put in the front lines to face the bulk of the battle."
Swamp_Of_Dread="Swamp Of Dread"
Swamp_Of_Dread_objectives="
Victory:
@Defeat all enemy leaders
Defeat
Overwinning:
@Versla all vijandige leiders
Verslagen
#Dood van Konrad
#Dood van Delfador"
Swordsman="Swordsman"
Swordsman_description="The swordsman is the base of the human armies. These young soldiers are given basic training and put in the front lines to face the bulk of the battle."
The_Bay_of_Pearls="The Bay of Pearls"
The_Bay_of_Pearls_objectives="
Victory:
@Defeat both enemy leaders
Defeat:
Overwinning:
@Versla both vijandige leiders
Verslagen:
#Dood van Konrad
#Turns run out"
#Geen beurten meer"
The_Dwarven_Doors="The Dwarven Doors"
The_Dwarven_Doors_objectives="
Victory:
Overwinning:
@Move Konrad to entrance of the Dwarven Kingdom.
Defeat:
Verslagen:
#Dood van Konrad
#Dood van Delfador
#Dood van Kalenz"
The_Elves_Besieged="The Elves Besieged"
The_Elves_Besieged_objectives="
Victory:
Overwinning:
@Move Konrad to the signpost in the north-west
Defeat:
Verslagen:
#Dood van Konrad
#Dood van Delfador
#Turns run out"
#Geen beurten meer"
The_Ford_of_Abez="The Ford of Abez"
The_Ford_of_Abez_objectives="
Victory:
Overwinning:
@Move Konrad to the North side of the river.
Defeat:
Verslagen:
#Dood van Konrad
#Dood van Delfador
#Dood van Kalenz"
The_Isle_of_Anduin="The Isle of Anduin"
The_Isle_of_Anduin_objectives="
Victory:
@Defeat enemy leader
Defeat:
Overwinning:
@Versla vijandige leider
Verslagen:
#Dood van Konrad
#Dood van Delfador
#Turns run out"
#Geen beurten meer"
The_Liberation_Front="The Liberation Front"
The_Liberation_Front_objectives="
Victory:
@Defeat All three Orc Leaders
Defeat:
Overwinning:
@Versla All three Orc Leaders
Verslagen:
#Dood van Konrad
#Dood van Delfador
#Dood van Kalenz
@ -355,33 +354,33 @@ Defeat:
#Time runs out"
The_Lost_General="The Lost General"
The_Lost_General_objectives="
Victory:
@Defeat all enemy leaders
Defeat:
Overwinning:
@Versla all vijandige leiders
Verslagen:
#Dood van Konrad
#Dood van Delfador
#Dood van Kalenz"
The_Princess_of_Wesnoth="The Princess of Wesnoth"
The_Princess_of_Wesnoth_objectives="
Victory:
Overwinning:
@Force Li'sar's surrender
Defeat:
Verslagen:
#Dood van Konrad
#Dood van Delfador
#Dood van Kalenz
#Turns run out"
#Geen beurten meer"
The_Siege_of_Elensefar="The Siege of Elensefar"
The_Siege_of_Elensefar_objectives="
Victory:
@Defeat both enemy leaders
Defeat:
Overwinning:
@Versla both vijandige leiders
Verslagen:
#Dood van Konrad
#Turns run out"
#Geen beurten meer"
The_Valley_of_Death-The_Princesss_Revenge="The Valley of Death - The Princess's Revenge"
The_Valley_of_Death-The_Princesss_Revenge_objectives="
Victory:
Overwinning:
@Survive for two days
Defeat:
Verslagen:
#Dood van Konrad
#Dood van Delfador
#Dood van Kalenz"
@ -488,8 +487,8 @@ The white mage is potent in battle against the undead, which experience high dam
create_new_game="Creeer spel"
date_format="%a %b %d %H:%M %Y"
deep water="Diep Water"
defeat_heading="Verlies"
defeat_message="Je hebt verloren!"
Verslagen_heading="Verlies"
Verslagen_message="Je hebt verloren!"
defense="Verdediging"
describe_unit="Omschrijving"
difficulty_level="Selecteer moeilijkheidsgraad:"
@ -498,7 +497,7 @@ The white mage is potent in battle against the undead, which experience high dam
early_finish_bonus="vroege finish bonus"
elves="Elven"
end_game_heading="Einde"
# end_game_message="You have reached the end of the currently playable levels"
end_game_message="Er zijn geen scenario's meer in deze campagne"
end_turn="Eind Beurt"
error_no_campaigns="Er zijn geen campagnes beschikbaar"
fifty_percent="80% van het goud wordt behouden in het volgende scenario"
@ -580,12 +579,12 @@ The white mage is potent in battle against the undead, which experience high dam
mountains="Bergen"
movement="Verplaatsing"
moves="Bereik"
# msg10_10="If this is true, Konrad, perhaps we should take another route and go around the mountain, rather then to try and defeat these new foes."
# msg10_10="If this is true, Konrad, perhaps we should take another route and go around the mountain, rather then to try and Verslagen these new foes."
# msg10_11="What say you, Delfador?"
# msg10_12="No! We do not have the time to waste, we make for top of the pass, beware of mountain trolls, and do not stray too close to the water!"
# msg10_13="The shinsplitters will aid you in your quest, look, they arise from the villages to the east, the mighty shinsplitters!!! To battle!"
# msg10_2="Look Konrad, before us lies the great road built by the dwarves!"
# msg10_20="Well, we have defeated our foes let us hope the mountain does not defeat us!"
# msg10_20="Well, we have Verslagened our foes let us hope the mountain does not Verslagen us!"
# msg10_21="I wish you all the best on your journey, I must return to my village and take care of my family, dwarven hospitality will welcome you, wherever you go friends!"
# msg10_22="Let us move onward!"
# msg10_3a="But, I can hardly see, with all this mist around!"
@ -674,50 +673,49 @@ The white mage is potent in battle against the undead, which experience high dam
msg1_10="Laat ze maar komen. We bestrijden ze met alles wat we hebben."
msg1_11="Wees voorzichtig, Konrad! Zorg goed voor hem, Delfador!"
msg1_12="En zo het begon..."
# msg1_13="Okay, we have made it this far! But where do we go next?"
# msg1_14="We must travel north, and try to make it to the Isle of Anduin. Hopefully there we will find refuge."
# msg1_15="Of course you are right, Delfador. But what will become of the Elves here?"
# msg1_16="The Elves will fight. They may even prevail. But I fear things do not bode well for them. Let us not speak of it now. Onward!"
# msg1_17="Good luck Konrad! Don't worry about us, we will fight as best we can!"
# msg1_18="I....I don't think I can make it anymore"
# msg1_19="Prince...you must keep fighting! Nooooooo!"
msg1_13="Goed, we hebben het gehaald! Maar waar gaan we nu naar toe?"
msg1_14="We reizen naar het zuiden en proberen naar het eiland van Anduin te komen. Hopelijk vinden we daar een onderkomen"
msg1_15="Natuurlijk heb je gelijk, Delfador. Maar wat zal er met de Elven hier gebeuren?"
msg1_16="De Elven zullen doorvechten. Ze zullen het misschien zelfs overleven. Maar het ziet er niet goed uit voor hen. Laat ons daar nu niet over spreken. Voorwaarts!"
msg1_17="Succes, Konrad! Maak je geen zorgen over ons. We vechten zo goed we kunnen!"
msg1_18="Ik....ik haal het niet meer"
msg1_19="Prins...Je moet blijven vechten! Neeeee!"
msg1_2="Meester Delfador! Kijk, Orks komen van alle richtingen! Wat moeten we doen?"
# msg1_20="It is over, I am doomed...."
# msg1_21="I have....have failed in my duty to protect the prince, I am defeated"
# msg1_22="Don't die! Delfador! Please, you have to stay alive!"
# msg1_23="Ugh"
# msg1_24="Oh no! We have run out of time, they have arrived with reinforcements..."
# msg1_25="Die villain, die!"
# msg1_26="Only the foolish oppose me!"
# msg1_27="I am Galdrad. You will have to fight me to get any further!"
# msg1_28="Only a fool would dare to attack me!"
# msg1_28a="I am Delfador the Great, prepare to die!"
# msg1_29="Let me through you rogue!"
msg1_20="Het is over, ik ben verloren...."
msg1_21="Ik heb.... heb gefaald in mijn plicht om de prins te beschermen. Ik ben verslagen"
msg1_22="Blijf leven! Delfador! Alstublieft, U mag niet dood!"
msg1_23="Ugh"
msg1_24="Oh nee! We zijn te langzaam geweest. Er komen versterkingen aan bij de Orks...."
msg1_25="Sterf, schurk, sterf!"
msg1_26="Alleen de dommen houden me tegen!"
msg1_27="Ik ben Galdrad. Je moet eerst mij verslaan, voor je verder kan!"
msg1_28="Alleen een gek durft het aan mij aan te vallen!"
msg1_28a="Ik ben Delfador the Grote, wees klaar om te sterven!"
msg1_29="Laat me door, etter!"
msg1_3="Er zijn er teveel om te bevechten. We moeten ontsnappen!"
# msg1_30="They are destroying our home!"
# msg1_31="There can be no looking back. We must go quickly!"
msg1_30="Ze vernietigen ons huis!"
msg1_31="Kijk niet terug! We moeten door en snel!"
msg1_4="Maar waar naar toe? Dit is ons enige huis! En wat gebeurt er met de Elven?"
msg1_5="We zullen met hen strijden, maar jij moet weg, Konrad. Het is van groot belang dat jij ontsnapt!"
msg1_6="We gaan naar het noorden. Misschien kunnen we het eiland van Anduin bereiken. Als we dat halen, dan zullen we zeker veilig zijn. Konrad, we moeten wat Elven inhuren om ons te helpen en dan moet je naar de wegwijzer in het noord-westen. Ik zal je beschermen!"
msg1_5="We zullen tegen hen strijden, maar jij moet weg, Konrad. Het is van groot belang dat jij ontsnapt!"
msg1_6="We gaan naar het zuiden. Misschien kunnen we het eiland van Anduin bereiken. Als we dat halen, dan zullen we zeker veilig zijn. Konrad, we moeten wat Elven inhuren om ons te helpen en dan moet je naar de wegwijzer in het noord-westen. Ik zal je beschermen!"
msg1_7="Da's goed, laten we opschieten!"
msg1_8="Val de Elven aan, bezet hun dorpen, laten we dit land claimen voor de Koningin!"
msg1_9="Haha! We snijden die vieze Elven aan stukjes!"
# msg1b_1="We should be able to board a ship at Blackwater Port, but it seems the Orcs are heading there too. One of my old apprentices has settled in these lands - I am sure he will help us!"
# msg1b_10="I could offer you a ship - I sent it to the open sea with the elder and the children, but it should arrive back in port soon."
# msg1b_11="Thank you, sir."
# msg1b_11b="I only hope that we will do as well the next time the evil Orcs attack us."
# msg1b_12="We should embark now."
# msg1b_13="I failed to the Blackwater port people...."
# msg1b_14="Without his help, we will be unable to use the ships, there is no hope..."
# msg1b_2="Defaldor, some Orcs are following our trail! We must make haste!"
# msg1b_3="Delfaldor, my old master, your arrival bring us the light of hope.
We heard the news that the orcs were attacking the elvish woods and some of them where headed here to attack us also, but our defenses are still weak."
# msg1b_4="We will help you fight them off."
# msg1b_5a="I shall send one of my mages to aid you. Recruit more mages, and perhaps some horsemen, who have fought very well for us against the crown. I need a few days to summon aid."
# msg1b_6="The defenses are now summoned."
# msg1b_7="Geeee!! Too many mages, we had better retreat now!"
# msg1b_8="Thank you for the help, friends."
# msg1b_9="We are seeking transport to the isle of Anduin."
msg1_9="Haha! We snijden die vieze Elven aan stukjes!"
msg1b_1="Het zou mogelijk moeten zijn om aan boord van een schip te komen in de Zwartwater haven, maar het lijkt er op dat de Orks ook deze kant op komen. Een van mijn oude leerlingen heeft zich hier gevestigd - Ik weet zeker dat hij ons wil helpen."
msg1b_10="Ik can u een schip aanbieden - ik heb het naar de open zee gestuurd met de ouderen en de kinderen, maar het zal snel weer terug zijn."
msg1b_11="Dank U, meneer."
msg1b_11b="Ik hoop alleen dat we het de volgende keer ook zo goed doen, als die vuile Orks ons weer aanvallen."
msg1b_12="We moeten nu aan boord."
msg1b_13="Ik heb gefaald voor de mensen van de Zwartwater haven...."
msg1b_14="Zonder zijn hulp, kunnen de schepen niet krijgen. Er is geen hoop..."
msg1b_2="Defaldor, sommige Orks volgen ons spoor! We moeten opschieten!"
msg1b_3="Delfaldor, my oude meester, Uw komst brengt ons het licht van hoop. We hoorden dat de Orks in het Elvenbos aanvielen en dat sommige ook hier naar toe kwamen om ons aan te vallen. Onze verdediging is alleen nog zwak."
msg1b_4="We zullen je helpen hen te bevechten."
msg1b_5a="Ik zal een van mijn magiër sturen om jullie te helpen. Huur meer magiërs in, en misschien wat paardrijders, die voor ons zeer goed tegen de troon hebben gevochten. Ik zal een paar dagen nodig hebben om hulp te regelen."
msg1b_6="The defenses are now summoned."
msg1b_7="Waaaah!! Veel te veel magiërs, we moeten terugtrekken!"
msg1b_8="Dank voor de hulp, vrienden."
msg1b_9="We zoeken transport naar het eiland van Anduin."
# msg2_1="And so the party landed on the Isle of Anduin..."
# msg2_10="Have you not heard? Many mermen have been captured, and are being farmed as pearl harvesters at the Bay of Pearls. If only someone would rescue them!"
# msg2_11="Let us go and rescue them then!"
@ -736,7 +734,7 @@ We heard the news that the orcs were attacking the elvish woods and some of them
# msg3_10="But...but...how can this be happening to me?"
# msg3_11="Who was that idiot?"
# msg3_12="Free at last! Now death to the Orcs!"
# msg3_13="Now that we are free, together we can defeat our oppressors!"
# msg3_13="Now that we are free, together we can Verslagen our oppressors!"
# msg3_13a="Death to the orcs! Come, let us all fight them men!"
# msg3_14="Freedom! Now where are those Orcs? Let me at em!"
# msg3_15="Thank you for rescuing us! Now we can help you fight the evil Orcs!
@ -767,14 +765,14 @@ The main cage where they keep most of the mermen is in the south-east!"
# msg4_1="But the road to Elensefar was a treacherous one. Konrad and his men were set upon by the fiends of the undead."
# msg4_10="Surprise! Searching for Mages, all I get is elves!"
# msg4_11="The temple seems to be empty."
# msg4_12a="It has been an honor to have helped you defeat the undead, my lord. I must now return to my home. I feel that our paths may cross again one day, perhaps when your need against the undead hordes is greater still."
# msg4_12a="It has been an honor to have helped you Verslagen the undead, my lord. I must now return to my home. I feel that our paths may cross again one day, perhaps when your need against the undead hordes is greater still."
# msg4_2="My lord! In yonder ruins there seems to be some movement!"
# msg4_3="It looks like there are the undead there! Prepare for battle men!"
# msg4_4="To arms!"
# msg4_5="Ahh, a party of Elves approaches. Soon we shall have Elven zombies serving us!"
# msg4_6="There are some ancient temples to the north-west, I wonder what might be inside them!"
# msg4_7="Looks like there is somebody hidden in the temple."
# msg4_8="I was hiding in this holy place planning how to defeat the evil undeads, now I with your help, we can destroy them."
# msg4_8="I was hiding in this holy place planning how to Verslagen the evil undeads, now I with your help, we can destroy them."
# msg4_9="Looks like there is somebody hidden in the temple."
# msg4_moredie="Fight on against the undead without me, friends!"
# msg5_1="The party arrived at Elensefar at last, but found that the city had already fallen to the evil Orcs."
@ -824,7 +822,7 @@ The main cage where they keep most of the mermen is in the south-east!"
# msg6_22="You get paid to kill them, so go!"
# msg6_23="Somebody! Kill these intruders, now!"
# msg6_24="Uggh will kill the slims!"
# msg6_25="Ogres! I need more ogres to defeat them!"
# msg6_25="Ogres! I need more ogres to Verslagen them!"
# msg6_26="Surely an ogre will crush them!"
# msg6_27="I surrender! Don't hurt me, imposter."
# msg6_28="I said before I'm not an imposter, but if you yield, I will spare your life."
@ -837,8 +835,8 @@ The main cage where they keep most of the mermen is in the south-east!"
# msg6_34="Good day, princess. Come men, to the northern road!"
# msg6_35="(hehe, little do they know just how many undead have wandered the northern road of late. Surely they are doomed!)"
# msg6_36="No! It can't end like this!"
# msg6_37="Argh! I have been defeated!"
# msg6_38="With Kalenz slain, it is hopeless. We are defeated."
# msg6_37="Argh! I have been Verslagened!"
# msg6_38="With Kalenz slain, it is hopeless. We are Verslagened."
# msg6_4="I'm no imposter, it seems that your mother has lied to you about it."
# msg6_5="It's no use reasoning. There is only one thing she will understand. To arms!"
# msg6_6="This is taking too much time, I best call some reinforcements!"
@ -873,7 +871,7 @@ The main cage where they keep most of the mermen is in the south-east!"
# msg8_5b="Well, let's start climbing that mountain!"
# msg8_5c="It appears we are not the only ones who are interested in this mountain. Once again the Queen opposes us!"
# msg8_5d="Quickly men! Onward!"
# msg8_6="We have defeated them! Now what do we do?"
# msg8_6="We have Verslagened them! Now what do we do?"
# msg8_7="We must continue north. It is too late to return to the safety of Elensefar or Anduin before winter befalls us. Thus we must cross the great river and continue toward the land of the Dwarves. Come let us go!"
# msg8_8="With these gryphon eggs we should be able to breed gryphons that will serve us. That will let us hire gryphon riders!"
# msg8_9b="Let us continue onward!"
@ -891,7 +889,7 @@ The main cage where they keep most of the mermen is in the south-east!"
# msg9_2="Really? So what happened, Delfador?"
# msg9_20a="Not her again! Quick, we must make haste!"
# msg9_3="The forces of the king were encamped here. The forces of the north were camped on the north side of the river. For three days and three nights the armies faced each other, neither one willing to ford the river. On the fourth day, the northern armies crossed the river, and attacked us."
# msg9_4b="And then....we were defeated?"
# msg9_4b="And then....we were Verslagened?"
# msg9_5="We were winning the battle. We were repelling them."
# msg9_6="Until the king's son, in the heat of battle, until he turned on the king!"
# msg9_7b="But you avenged the murder. You killed the prince, right Delfador?"
@ -905,10 +903,10 @@ The main cage where they keep most of the mermen is in the south-east!"
# msg9_a6="They have made it away! I cannot believe it! We must make chase after them over the river! We will meet again, foul imposter!"
# msg9_a7="Do you think she's really going to chase us Delfador?"
# msg9_a8="It surely looks like she will try, but the sea creatures will make it difficult for her. We must continue onward. If she makes it across before winter, then so be it!"
# msg_delfador_die="No! This is the end! We have been defeated!"
# msg_delfador_die="No! This is the end! We have been Verslagened!"
# msg_doors_lisar="Whew! We make our way through the dangerous fog of the mountains, and now there is all this chaos before us! Come on men! We must make it into the mines, for they are still ahead of us!"
# msg_kalenz_die="Argh! I am finished with!"
# msg_konrad_die="We are vanquished, for I have been defeated!"
# msg_konrad_die="We are vanquished, for I have been Verslagened!"
# msg_lisar_die="I can't believe it should end like this!"
# msgcrossroads1="Stay on the path!"
# msgcrossroads2="Stay out of the forrest!"
@ -926,7 +924,7 @@ The main cage where they keep most of the mermen is in the south-east!"
# msgsnowplains2="This sword may prove useful on our journy ahead. It must be in one of the towns before us."
# msgswamp1="This land is cursed. The Lichen have lived here for years amassing great armies and fortunes."
# msgswamp2="The Lichen are all over this swamp. I hope I have made a wise choice to come down this path."
# msgswamp3="Each of the Lichen leaders will have a pile of gold you can take, if they are defeated. Don't stretch you armies to thin though, we still must pass threw this swamp to the north."
# msgswamp3="Each of the Lichen leaders will have a pile of gold you can take, if they are Verslagened. Don't stretch you armies to thin though, we still must pass threw this swamp to the north."
multiplayer1="The Isle of Anduin"
multiplayer2="The Three Rivers"
multiplayer3="The Valley of Death"
@ -980,7 +978,7 @@ The main cage where they keep most of the mermen is in the south-east!"
remote_host="Kies een connectie"
rename_unit="Hernoem manschap"
replay_game_message="Laat een herhaling zien tot het punt van opslaan?"
retained_gold="Overgebleven goud ....Retaining"
retained_gold="Behouden goud"
road="Weg"
sand="Zand"
save_confirm_message="Het spel is opgeslagen"
@ -1034,7 +1032,7 @@ The main cage where they keep most of the mermen is in the south-east!"
tut10="Ja, precies! Het is ook belangrijk om dorpen, die van mij zijn, af te pakken"
tut11="Goed mannen, naar de dorpen dan!"
tut12="Welke type manschappen moet ik inhuren, Delfador?"
tut13="Je moet goed naar hun vaardigheden kijken. Eerst wil je snelle manschappen, die voor je zo veel mogelijk dorpen veroveren. Daarna maken waarschijnlijk de elf-soldaten het grootste gedeelte van je leger uit. Denk er aan dat elven heel goed vechten in het bos. Paardrijders zijn prima op open grond. Magiërs zijn een goede ondersteuning en kunnen bijna hetzelfde worden ingezet als boogmannen. Als magiërs meer ervaren worden, dan worden ze erg machtig."
tut13="Je moet goed naar hun vaardigheden kijken. Eerst wil je snelle manschappen, die voor je zo veel mogelijk dorpen veroveren. Daarna maken waarschijnlijk de elf-soldaten het grootste gedeelte van je leger uit. Denk er aan dat elven heel goed vechten in het bos. Paardrijders zijn prima op open grond. Magiërs zijn een goede ondersteuning en kunnen bijna hetzelfde worden ingezet als boogschutters. Als magiërs meer ervaren worden, dan worden ze erg machtig."
tut14="Als je een vijand aanvalt, dan kan je kiezen welk wapen je wil gebruiken. Je kan dan de kans bekijken op raken en geraakt worden en hoeveel schade dat doet."
tut15="Leuk geprobeert, Konrad, maar er moet nog wel wat verbeterd worden."
tut16="Je hebt me verslagen, Konrad. Gefeliciteerd met je vechtkunst. Je bent geslaagd voor deze test."
@ -1048,7 +1046,7 @@ The main cage where they keep most of the mermen is in the south-east!"
tut9="Dus het is belangrijk om de controle over veel dorpen te krijgen, zodat ik veel geld krijg om veel soldaten in te huren?"
tutorial_button="Oefeningen"
# und1_1="As the sun set over a land far removed from the war that was happening in Wesnoth, a new war was brewing, between brothers..."
# und1_10="I... have failed to win this battle, I am defeated. I will not believe it."
# und1_10="I... have failed to win this battle, I am Verslagened. I will not believe it."
# und1_11="Die, yes die, and go to the Land of the Dead. Perhaps one day you will be back under my command!"
# und1_12="Didn't I tell you so?!"
# und1_13="And by my own hands you died!"
@ -1135,7 +1133,7 @@ The main cage where they keep most of the mermen is in the south-east!"
# weapon_special_charge="charge"
weapon_special_drain="uitzuiging"
weapon_special_magical="magisch"
# weapon_special_marksman="specialist/vakman"
# weapon_special_marksman="boogschutter"
weapon_special_plague="plaag"
weapon_special_poison="gif"
weapon_special_slow="traag"

View file

@ -122,7 +122,7 @@ choose_campaign="Choose the campaign you want to play:"
difficulty_level="Select difficulty level:"
EASY="Fighter (easy)"
NORMAL="Hero (medium)"
NORMAL="*Hero (medium)"
HARD="Champion (hard)"
no_leader_to_recruit="You don't have a leader to recruit with."
@ -194,6 +194,7 @@ create_new_game="Create Game"
name_of_game="Name of game"
map_to_play="Map to play"
village_gold="Village Gold"
turns="Turns"
login="Login"
must_login="You must log in to this server"
@ -204,6 +205,7 @@ advance_unit_heading="Advance Unit"
advance_unit_message="What should our victorious unit become?"
version_save_message="This save is from a different version of the game. Do you want to try to load it?"
bad_save_message="The file you have tried to load is corrupt"
not_multiplayer_save_message="This is not a multiplayer save"
no_saves_heading="No Saved Games"
no_saves_message="There are no saved games to load.
(Games are saved automatically when you complete a scenario)"
@ -235,12 +237,15 @@ upkeep="Upkeep"
income="Income"
name="Name"
type="Type"
hp="HP"
xp="XP"
moves="Moves"
location="Location"
level="level"
message="Message"
speak="Speak"
describe_unit="Describe Unit"
rename_unit="Rename Unit"
scenario_objectives="Scenario Objectives"

File diff suppressed because it is too large Load diff

View file

@ -4,6 +4,8 @@
turns=28
id=tutorial
next_scenario=tutorial2
music=wesnoth-4.ogg
{DAWN}
{MORNING}
@ -25,7 +27,7 @@ Defeat:
experience=0
side=1
canrecruit=1
recruit=Elvish Fighter,Elvish Archer,Horseman,Mage,Elvish Scout
recruit=Elvish Fighter,Elvish Archer,Horseman,Mage,Elvish Scout, Elvish Shaman
facing=reverse
enemy=2
gold=200
@ -39,7 +41,7 @@ Defeat:
experience=0
side=2
canrecruit=1
recruit=Elvish Fighter,Elvish Archer,Horseman
recruit=Elvish Fighter,Elvish Archer,Horseman,Elvish Shaman
gold=60
enemy=1
[/side]

183
data/tutorial2.cfg Normal file
View file

@ -0,0 +1,183 @@
[tutorial]
name=The Elven Training Grounds (part II)
map=map-tutorial
turns=28
id=tutorial2
next_scenario=null
{DAWN}
{MORNING}
{AFTERNOON}
{DUSK}
{FIRST_WATCH}
{SECOND_WATCH}
objectives="Victory:
@Defeat Delfador
Defeat:
#Death of Konrad
#Turns run out"
[side]
race=Elves
type=Fighter
description=Konrad
experience=0
side=1
canrecruit=1
recruit=Elvish Fighter,Elvish Archer,Horseman,Mage,Elvish Scout,Elvish Shaman
facing=reverse
enemy=2
controller=human
[/side]
[side]
type=Elder Mage
description=Delfador
experience=0
side=2
canrecruit=1
recruit=Elvish Fighter,Elvish Archer,Horseman,Elvish Shaman
gold=70
enemy=1
[/side]
[event]
name=start
[message]
id=tut2_1
description=Delfador
message="Now, we have swapped places. I'm going to teach you about recall."
[/message]
[message]
id=tut2_2
description=Korad
message="Recall?"
[/message]
[message]
id=tut2_3
description=Delfador
message="Soldiers that have fighted for you in past battles and survived could be called again to serve you."
[/message]
[message]
id=tut2_4
description=Konrad
message="Ahhh, I see so I can have more experienced soldiers at my side."
[/message]
[message]
id=tut2_5
description=Delfador
message="Yes, that's the point."
[/message]
[/event]
[event]
name=turn 3
[command]
[message]
id=tut2_6
description=Delfador
message="I will recall some experienced friends of mine too."
[/message]
[/command]
[command]
[unit]
description=Lumonieth
type=Elvish Captain
side=2
x=11
y=18
facing=reverse
[/unit]
[/command]
[command]
[message]
id=tut2_7
description=Lumonieth
message="Greetings, Konrad!"
[/message]
[message]
id=tut2_8
description=Delfador
message="Experienced units are more powerfull and usually have special skills too."
[/message]
[message]
id=tut2_9
description=Konrad
message="Hi, Lumonieth, special skills?"
[/message]
[message]
id=tut2_10
description=Lumonieth
message="I was trained to lead troops, I can make all soldiers around me fight better."
[/message]
[message]
id=tut2_11
description=Delfador
message="XXXXXXXXXXXXXXXXXXXXXXXXX"
[/message]
[/command]
[/event]
[event]
name=turn 3
[message]
id=tut2_12
description=Konrad
message=""
[/message]
[message]
id=tut2_13
description=Delfador
message=""
[/message]
[/event]
[event]
name=attack
[filter]
side=2
[/filter]
[message]
id=tut2_14
description=Delfador
message=""
[/message]
[/event]
[event]
name=die
[filter]
description=Konrad
[/filter]
[message]
id=tut2_15
description=Delfador
message="A nice try, Konrad, but it seems your skills have much to be improved still."
[/message]
[/event]
[event]
name=die
[filter]
description=Delfador
[/filter]
[message]
id=tut2_16
description=Delfador
message="You have bested me, Konrad. Congratulations on your skill. You have passed the second training test."
[/message]
[/event]
[/tutorial]

View file

@ -2,6 +2,7 @@
name=Ancient Lich
race=undead
image=undead-ancient-lich.png
image_defensive=ancient-lich-defend.png
hitpoints=80
movement_type=undeadfoot
movement=6
@ -17,9 +18,14 @@ get_hit_sound=groan.wav
name=touch
type=cold
range=short
damage=10
damage=9
number=4
special=drain
[frame]
begin=-100
end=100
image=undead-ancient-lich-attack.png
[/frame]
[/attack]
[attack]
name=magic
@ -28,6 +34,11 @@ get_hit_sound=groan.wav
range=long
damage=15
number=5
[frame]
begin=-250
end=0
image=undead-ancient-lich-attack.png
[/frame]
[missile_frame]
begin=-200
end=0

View file

@ -2,6 +2,7 @@
name=Arch Mage
race=human
image=arch-mage.png
image_defensive=arch-mage-defend.png
hitpoints=58
movement_type=smallfoot
[resistance]
@ -31,10 +32,23 @@ get_hit_sound=groan.wav
special=magical
damage=12
number=4
[missile_frame]
[sound]
time=-200
sound=fire.wav
[/sound]
[frame]
begin=-250
end=-100
image=arch-mage-attack2.png
[/frame]
[frame]
begin=-100
end=0
image=arch-mage.png
[/frame]
[/missile_frame]
[missile_frame]
begin=-100
end=0

View file

@ -1,10 +1,10 @@
[unit]
name=Dark Adept
race=undead
race=human
image=undead-adept.png
image_defensive=undead-adept-defend.png
hitpoints=28
movement_type=undeadfoot
movement_type=smallfoot
movement=5
experience=48
level=1

View file

@ -35,5 +35,11 @@ get_hit_sound=groan.wav
range=long
damage=6
number=2
[missile_frame]
begin=-100
end=0
image=missiledagger-n.png
image_diagonal=missiledagger-ne.png
[/missile_frame]
[/attack]
[/unit]

View file

@ -46,6 +46,21 @@ get_hit_sound=groan.wav
range=long
damage=4
number=2
[sound]
time=-100
sound=firearrow.wav
[/sound]
[sound]
time=0
sound=arrow-hit.wav
sound_miss=arrow-miss.wav
[/sound]
[missile_frame]
begin=-100
end=0
image=missile-n.png
image_diagonal=missile-ne.png
[/missile_frame]
[/attack]
[/unit]

View file

@ -1,10 +1,10 @@
[unit]
name=Necromancer
race=undead
race=human
image=undead-necromancer.png
image_defensive=undead-necromancer-defend.png
hitpoints=58
movement_type=undeadfoot
movement_type=smallfoot
movement=5
experience=48
level=2

View file

@ -28,5 +28,11 @@ get_hit_sound=groan.wav
damage=5
number=4
special=poison
[missile_frame]
begin=-100
end=0
image=missiledagger-n.png
image_diagonal=missiledagger-ne.png
[/missile_frame]
[/attack]
[/unit]

View file

@ -11,7 +11,7 @@ alignment=chaotic
advanceto=Rogue
cost=12
usage=fighter
unit_description="Thieves are deft of foot, and elusive, making them diffult to hit. Being skilled at backstabbing, thieves do double damage when attacking an enemy that has an ally of the thief on the opposite side of him. Being of chaotic disposition, thieves fight better at night than at day."
unit_description="Thieves are deft of foot, and elusive, making them difficult to hit. Being skilled at backstabbing, thieves do double damage when attacking an enemy that has an ally of the thief on the opposite side of him. Being of chaotic disposition, thieves fight better at night than at day."
get_hit_sound=groan.wav
[attack]
name=dagger

View file

@ -2,6 +2,7 @@
name=Walking Corpse
race=undead
image=undead-zombie.png
image_defensive==undead-zombie-attack.png
hitpoints=16
movement_type=undeadfoot
movement=4

View file

@ -11,7 +11,7 @@ alignment=chaotic
advanceto=Goblin Knight,Goblin Pillager
cost=17
usage=scout
unit_desc="Being smaller and weaker than the orcs, the goblins train large wolfs to mount and use as fast scouts for the goblinoid army. Having being raised in the orcs dark caverns, the wolfs and their riders can even brave the mountains, unlike most other mounted units."
unit_description="Being smaller and weaker than the orcs, the goblins train large wolfs to mount and use as fast scouts for the goblinoid army. Having being raised in the orcs dark caverns, the wolfs and their riders can even brave the mountains, unlike most other mounted units."
get_hit_sound=groan.wav
[attack]
name=fangs

17
icons/Makefile.am Normal file
View file

@ -0,0 +1,17 @@
appicondir = $(datadir)/icons
appicon_DATA = ../images/wesnoth-icon.png
desktopdir = $(datadir)/applications
dist_desktop_DATA = wesnoth.desktop
if GNOME1
gnome1desktopdir = @GNOME1_DESKTOP@
gnome1desktop_DATA = $(dist_desktop_DATA)
endif
if KDE
kdedesktopdir = @KDE_DESKTOP@
kdedesktop_DATA = $(dist_desktop_DATA)
kdeicondir = @KDE_ICON@
kdeicon_DATA = $(appicon_DATA)
endif

395
icons/Makefile.in Normal file
View file

@ -0,0 +1,395 @@
# Makefile.in generated by automake 1.7.8 from Makefile.am.
# @configure_input@
# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
# Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
pkgdatadir = $(datadir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
top_builddir = ..
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
INSTALL = @INSTALL@
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
ACLOCAL = @ACLOCAL@
AMDEP_FALSE = @AMDEP_FALSE@
AMDEP_TRUE = @AMDEP_TRUE@
AMTAR = @AMTAR@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CXX = @CXX@
CXXDEPMODE = @CXXDEPMODE@
CXXFLAGS = @CXXFLAGS@
CYGPATH_W = @CYGPATH_W@
DATADIR = @DATADIR@
DATA_FILES = @DATA_FILES@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EDITOR_FALSE = @EDITOR_FALSE@
EDITOR_TRUE = @EDITOR_TRUE@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
FONT_FILES = @FONT_FILES@
GNOME1_DESKTOP = @GNOME1_DESKTOP@
GNOME1_FALSE = @GNOME1_FALSE@
GNOME1_TRUE = @GNOME1_TRUE@
GNOME_CONFIG = @GNOME_CONFIG@
IMAGE_FILES = @IMAGE_FILES@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
KDE_CONFIG = @KDE_CONFIG@
KDE_DESKTOP = @KDE_DESKTOP@
KDE_FALSE = @KDE_FALSE@
KDE_ICON = @KDE_ICON@
KDE_TRUE = @KDE_TRUE@
LDFLAGS = @LDFLAGS@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LTLIBOBJS = @LTLIBOBJS@
MAKEINFO = @MAKEINFO@
MANUAL_FILES = @MANUAL_FILES@
MUSIC_FILES = @MUSIC_FILES@
OBJEXT = @OBJEXT@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
SDL_CFLAGS = @SDL_CFLAGS@
SDL_CONFIG = @SDL_CONFIG@
SDL_IMAGE_LIBS = @SDL_IMAGE_LIBS@
SDL_LIBS = @SDL_LIBS@
SDL_MIXER_LIBS = @SDL_MIXER_LIBS@
SDL_NET_LIBS = @SDL_NET_LIBS@
SDL_TTF_LIBS = @SDL_TTF_LIBS@
SERVER_FALSE = @SERVER_FALSE@
SERVER_TRUE = @SERVER_TRUE@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
SOUND_FILES = @SOUND_FILES@
STRIP = @STRIP@
TOOLS_FALSE = @TOOLS_FALSE@
TOOLS_TRUE = @TOOLS_TRUE@
UTIL_FILES = @UTIL_FILES@
VERSION = @VERSION@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
ac_ct_STRIP = @ac_ct_STRIP@
am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
bindir = @bindir@
build_alias = @build_alias@
datadir = @datadir@
exec_prefix = @exec_prefix@
host_alias = @host_alias@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localstatedir = @localstatedir@
mandir = @mandir@
oldincludedir = @oldincludedir@
prefix = @prefix@
program_transform_name = @program_transform_name@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
sysconfdir = @sysconfdir@
target_alias = @target_alias@
appicondir = $(datadir)/icons
appicon_DATA = ../images/wesnoth-icon.png
desktopdir = $(datadir)/applications
dist_desktop_DATA = wesnoth.desktop
@GNOME1_TRUE@gnome1desktopdir = @GNOME1_DESKTOP@
@GNOME1_TRUE@gnome1desktop_DATA = $(dist_desktop_DATA)
@KDE_TRUE@kdedesktopdir = @KDE_DESKTOP@
@KDE_TRUE@kdedesktop_DATA = $(dist_desktop_DATA)
@KDE_TRUE@kdeicondir = @KDE_ICON@
@KDE_TRUE@kdeicon_DATA = $(appicon_DATA)
subdir = icons
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
DIST_SOURCES =
DATA = $(appicon_DATA) $(dist_desktop_DATA) $(gnome1desktop_DATA) \
$(kdedesktop_DATA) $(kdeicon_DATA)
DIST_COMMON = $(dist_desktop_DATA) $(srcdir)/Makefile.in Makefile.am
all: all-am
.SUFFIXES:
$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.ac $(ACLOCAL_M4)
cd $(top_srcdir) && \
$(AUTOMAKE) --gnu icons/Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)
uninstall-info-am:
appiconDATA_INSTALL = $(INSTALL_DATA)
install-appiconDATA: $(appicon_DATA)
@$(NORMAL_INSTALL)
$(mkinstalldirs) $(DESTDIR)$(appicondir)
@list='$(appicon_DATA)'; for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
f="`echo $$p | sed -e 's|^.*/||'`"; \
echo " $(appiconDATA_INSTALL) $$d$$p $(DESTDIR)$(appicondir)/$$f"; \
$(appiconDATA_INSTALL) $$d$$p $(DESTDIR)$(appicondir)/$$f; \
done
uninstall-appiconDATA:
@$(NORMAL_UNINSTALL)
@list='$(appicon_DATA)'; for p in $$list; do \
f="`echo $$p | sed -e 's|^.*/||'`"; \
echo " rm -f $(DESTDIR)$(appicondir)/$$f"; \
rm -f $(DESTDIR)$(appicondir)/$$f; \
done
dist_desktopDATA_INSTALL = $(INSTALL_DATA)
install-dist_desktopDATA: $(dist_desktop_DATA)
@$(NORMAL_INSTALL)
$(mkinstalldirs) $(DESTDIR)$(desktopdir)
@list='$(dist_desktop_DATA)'; for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
f="`echo $$p | sed -e 's|^.*/||'`"; \
echo " $(dist_desktopDATA_INSTALL) $$d$$p $(DESTDIR)$(desktopdir)/$$f"; \
$(dist_desktopDATA_INSTALL) $$d$$p $(DESTDIR)$(desktopdir)/$$f; \
done
uninstall-dist_desktopDATA:
@$(NORMAL_UNINSTALL)
@list='$(dist_desktop_DATA)'; for p in $$list; do \
f="`echo $$p | sed -e 's|^.*/||'`"; \
echo " rm -f $(DESTDIR)$(desktopdir)/$$f"; \
rm -f $(DESTDIR)$(desktopdir)/$$f; \
done
gnome1desktopDATA_INSTALL = $(INSTALL_DATA)
install-gnome1desktopDATA: $(gnome1desktop_DATA)
@$(NORMAL_INSTALL)
$(mkinstalldirs) $(DESTDIR)$(gnome1desktopdir)
@list='$(gnome1desktop_DATA)'; for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
f="`echo $$p | sed -e 's|^.*/||'`"; \
echo " $(gnome1desktopDATA_INSTALL) $$d$$p $(DESTDIR)$(gnome1desktopdir)/$$f"; \
$(gnome1desktopDATA_INSTALL) $$d$$p $(DESTDIR)$(gnome1desktopdir)/$$f; \
done
uninstall-gnome1desktopDATA:
@$(NORMAL_UNINSTALL)
@list='$(gnome1desktop_DATA)'; for p in $$list; do \
f="`echo $$p | sed -e 's|^.*/||'`"; \
echo " rm -f $(DESTDIR)$(gnome1desktopdir)/$$f"; \
rm -f $(DESTDIR)$(gnome1desktopdir)/$$f; \
done
kdedesktopDATA_INSTALL = $(INSTALL_DATA)
install-kdedesktopDATA: $(kdedesktop_DATA)
@$(NORMAL_INSTALL)
$(mkinstalldirs) $(DESTDIR)$(kdedesktopdir)
@list='$(kdedesktop_DATA)'; for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
f="`echo $$p | sed -e 's|^.*/||'`"; \
echo " $(kdedesktopDATA_INSTALL) $$d$$p $(DESTDIR)$(kdedesktopdir)/$$f"; \
$(kdedesktopDATA_INSTALL) $$d$$p $(DESTDIR)$(kdedesktopdir)/$$f; \
done
uninstall-kdedesktopDATA:
@$(NORMAL_UNINSTALL)
@list='$(kdedesktop_DATA)'; for p in $$list; do \
f="`echo $$p | sed -e 's|^.*/||'`"; \
echo " rm -f $(DESTDIR)$(kdedesktopdir)/$$f"; \
rm -f $(DESTDIR)$(kdedesktopdir)/$$f; \
done
kdeiconDATA_INSTALL = $(INSTALL_DATA)
install-kdeiconDATA: $(kdeicon_DATA)
@$(NORMAL_INSTALL)
$(mkinstalldirs) $(DESTDIR)$(kdeicondir)
@list='$(kdeicon_DATA)'; for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
f="`echo $$p | sed -e 's|^.*/||'`"; \
echo " $(kdeiconDATA_INSTALL) $$d$$p $(DESTDIR)$(kdeicondir)/$$f"; \
$(kdeiconDATA_INSTALL) $$d$$p $(DESTDIR)$(kdeicondir)/$$f; \
done
uninstall-kdeiconDATA:
@$(NORMAL_UNINSTALL)
@list='$(kdeicon_DATA)'; for p in $$list; do \
f="`echo $$p | sed -e 's|^.*/||'`"; \
echo " rm -f $(DESTDIR)$(kdeicondir)/$$f"; \
rm -f $(DESTDIR)$(kdeicondir)/$$f; \
done
tags: TAGS
TAGS:
ctags: CTAGS
CTAGS:
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
top_distdir = ..
distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
distdir: $(DISTFILES)
@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
list='$(DISTFILES)'; for file in $$list; do \
case $$file in \
$(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
$(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
esac; \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
if test "$$dir" != "$$file" && test "$$dir" != "."; then \
dir="/$$dir"; \
$(mkinstalldirs) "$(distdir)$$dir"; \
else \
dir=''; \
fi; \
if test -d $$d/$$file; then \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
fi; \
cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
else \
test -f $(distdir)/$$file \
|| cp -p $$d/$$file $(distdir)/$$file \
|| exit 1; \
fi; \
done
check-am: all-am
check: check-am
all-am: Makefile $(DATA)
installdirs:
$(mkinstalldirs) $(DESTDIR)$(appicondir) $(DESTDIR)$(desktopdir) $(DESTDIR)$(gnome1desktopdir) $(DESTDIR)$(kdedesktopdir) $(DESTDIR)$(kdeicondir)
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-am
install-strip:
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
INSTALL_STRIP_FLAG=-s \
`test -z '$(STRIP)' || \
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
mostlyclean-generic:
clean-generic:
distclean-generic:
-rm -f $(CONFIG_CLEAN_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
clean: clean-am
clean-am: clean-generic mostlyclean-am
distclean: distclean-am
-rm -f Makefile
distclean-am: clean-am distclean-generic
dvi: dvi-am
dvi-am:
info: info-am
info-am:
install-data-am: install-appiconDATA install-dist_desktopDATA \
install-gnome1desktopDATA install-kdedesktopDATA \
install-kdeiconDATA
install-exec-am:
install-info: install-info-am
install-man:
installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-generic
pdf: pdf-am
pdf-am:
ps: ps-am
ps-am:
uninstall-am: uninstall-appiconDATA uninstall-dist_desktopDATA \
uninstall-gnome1desktopDATA uninstall-info-am \
uninstall-kdedesktopDATA uninstall-kdeiconDATA
.PHONY: all all-am check check-am clean clean-generic distclean \
distclean-generic distdir dvi dvi-am info info-am install \
install-am install-appiconDATA install-data install-data-am \
install-dist_desktopDATA install-exec install-exec-am \
install-gnome1desktopDATA install-info install-info-am \
install-kdedesktopDATA install-kdeiconDATA install-man \
install-strip installcheck installcheck-am installdirs \
maintainer-clean maintainer-clean-generic mostlyclean \
mostlyclean-generic pdf pdf-am ps ps-am uninstall uninstall-am \
uninstall-appiconDATA uninstall-dist_desktopDATA \
uninstall-gnome1desktopDATA uninstall-info-am \
uninstall-kdedesktopDATA uninstall-kdeiconDATA
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:

12
icons/wesnoth.desktop Normal file
View file

@ -0,0 +1,12 @@
[Desktop Entry]
Version=1.0
Encoding=UTF-8
Type=Application
Name=Battle for Wesnoth
GenericName=Strategy Game
Comment=A fantasy turn-based strategy game
Icon=wesnoth.png
FilePattern=wesnoth
TryExec=wesnoth
Exec=wesnoth
Category=Application;Game;StrategyGame;

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
images/arch-mage-defend.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 589 B

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 661 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 684 B

BIN
images/cockatrice.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 671 B

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
images/wesnoth-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

BIN
music/wesnoth-7.ogg Normal file

Binary file not shown.

BIN
music/wesnoth-8.ogg Normal file

Binary file not shown.

View file

@ -43,6 +43,7 @@ wesnoth_SOURCES = about.cpp \
language.cpp \
log.cpp \
map.cpp \
mapgen.cpp \
mouse.cpp \
multiplayer.cpp \
multiplayer_client.cpp \
@ -68,6 +69,7 @@ wesnoth_SOURCES = about.cpp \
widgets/menu.cpp \
widgets/slider.cpp \
widgets/textbox.cpp \
widgets/widget.cpp \
about.hpp \
actions.hpp \
ai.hpp \
@ -90,6 +92,7 @@ wesnoth_SOURCES = about.cpp \
language.hpp \
log.hpp \
map.hpp \
mapgen.hpp \
mouse.hpp \
multiplayer.hpp \
multiplayer_client.hpp \
@ -116,7 +119,8 @@ wesnoth_SOURCES = about.cpp \
widgets/combo.hpp \
widgets/menu.hpp \
widgets/slider.hpp \
widgets/textbox.hpp
widgets/textbox.hpp \
widgets/widget.hpp
#############################################################################
# Editor #
@ -143,6 +147,7 @@ wesnoth_editor_SOURCES = editor/editor.cpp \
language.cpp \
log.cpp \
map.cpp \
mapgen.cpp \
mouse.cpp \
network.cpp \
pathfind.cpp \
@ -164,6 +169,7 @@ wesnoth_editor_SOURCES = editor/editor.cpp \
widgets/menu.cpp \
widgets/textbox.cpp \
widgets/slider.cpp \
widgets/widget.cpp \
actions.hpp \
ai.hpp \
ai_attack.hpp \
@ -184,6 +190,7 @@ wesnoth_editor_SOURCES = editor/editor.cpp \
language.hpp \
log.hpp \
map.hpp \
mapgen.hpp \
mouse.hpp \
network.hpp \
pathfind.hpp \
@ -204,4 +211,5 @@ wesnoth_editor_SOURCES = editor/editor.cpp \
widgets/button.hpp \
widgets/menu.hpp \
widgets/textbox.hpp \
widgets/slider.hpp
widgets/slider.hpp \
widgets/widget.hpp

View file

@ -168,6 +168,7 @@ wesnoth_SOURCES = about.cpp \
language.cpp \
log.cpp \
map.cpp \
mapgen.cpp \
mouse.cpp \
multiplayer.cpp \
multiplayer_client.cpp \
@ -215,6 +216,7 @@ wesnoth_SOURCES = about.cpp \
language.hpp \
log.hpp \
map.hpp \
mapgen.hpp \
mouse.hpp \
multiplayer.hpp \
multiplayer_client.hpp \
@ -269,6 +271,7 @@ wesnoth_editor_SOURCES = editor/editor.cpp \
language.cpp \
log.cpp \
map.cpp \
mapgen.cpp \
mouse.cpp \
network.cpp \
pathfind.cpp \
@ -310,6 +313,7 @@ wesnoth_editor_SOURCES = editor/editor.cpp \
language.hpp \
log.hpp \
map.hpp \
mapgen.hpp \
mouse.hpp \
network.hpp \
pathfind.hpp \
@ -348,14 +352,15 @@ am_wesnoth_OBJECTS = about.$(OBJEXT) actions.$(OBJEXT) ai.$(OBJEXT) \
game_config.$(OBJEXT) game_events.$(OBJEXT) \
gamestatus.$(OBJEXT) hotkeys.$(OBJEXT) image.$(OBJEXT) \
intro.$(OBJEXT) key.$(OBJEXT) language.$(OBJEXT) log.$(OBJEXT) \
map.$(OBJEXT) mouse.$(OBJEXT) multiplayer.$(OBJEXT) \
multiplayer_client.$(OBJEXT) multiplayer_lobby.$(OBJEXT) \
network.$(OBJEXT) pathfind.$(OBJEXT) playlevel.$(OBJEXT) \
playturn.$(OBJEXT) preferences.$(OBJEXT) race.$(OBJEXT) \
replay.$(OBJEXT) sdl_utils.$(OBJEXT) show_dialog.$(OBJEXT) \
sound.$(OBJEXT) team.$(OBJEXT) terrain.$(OBJEXT) \
tooltips.$(OBJEXT) unit.$(OBJEXT) unit_types.$(OBJEXT) \
video.$(OBJEXT) button.$(OBJEXT) combo.$(OBJEXT) menu.$(OBJEXT) \
map.$(OBJEXT) mapgen.$(OBJEXT) mouse.$(OBJEXT) \
multiplayer.$(OBJEXT) multiplayer_client.$(OBJEXT) \
multiplayer_lobby.$(OBJEXT) network.$(OBJEXT) \
pathfind.$(OBJEXT) playlevel.$(OBJEXT) playturn.$(OBJEXT) \
preferences.$(OBJEXT) race.$(OBJEXT) replay.$(OBJEXT) \
sdl_utils.$(OBJEXT) show_dialog.$(OBJEXT) sound.$(OBJEXT) \
team.$(OBJEXT) terrain.$(OBJEXT) tooltips.$(OBJEXT) \
unit.$(OBJEXT) unit_types.$(OBJEXT) video.$(OBJEXT) \
button.$(OBJEXT) combo.$(OBJEXT) menu.$(OBJEXT) \
slider.$(OBJEXT) textbox.$(OBJEXT)
wesnoth_OBJECTS = $(am_wesnoth_OBJECTS)
wesnoth_LDADD = $(LDADD)
@ -368,14 +373,14 @@ am_wesnoth_editor_OBJECTS = editor.$(OBJEXT) actions.$(OBJEXT) \
game_config.$(OBJEXT) game_events.$(OBJEXT) \
gamestatus.$(OBJEXT) hotkeys.$(OBJEXT) image.$(OBJEXT) \
intro.$(OBJEXT) key.$(OBJEXT) language.$(OBJEXT) log.$(OBJEXT) \
map.$(OBJEXT) mouse.$(OBJEXT) network.$(OBJEXT) \
pathfind.$(OBJEXT) playlevel.$(OBJEXT) playturn.$(OBJEXT) \
preferences.$(OBJEXT) race.$(OBJEXT) replay.$(OBJEXT) \
sdl_utils.$(OBJEXT) show_dialog.$(OBJEXT) sound.$(OBJEXT) \
team.$(OBJEXT) terrain.$(OBJEXT) tooltips.$(OBJEXT) \
unit.$(OBJEXT) unit_types.$(OBJEXT) video.$(OBJEXT) \
button.$(OBJEXT) menu.$(OBJEXT) textbox.$(OBJEXT) \
slider.$(OBJEXT)
map.$(OBJEXT) mapgen.$(OBJEXT) mouse.$(OBJEXT) \
network.$(OBJEXT) pathfind.$(OBJEXT) playlevel.$(OBJEXT) \
playturn.$(OBJEXT) preferences.$(OBJEXT) race.$(OBJEXT) \
replay.$(OBJEXT) sdl_utils.$(OBJEXT) show_dialog.$(OBJEXT) \
sound.$(OBJEXT) team.$(OBJEXT) terrain.$(OBJEXT) \
tooltips.$(OBJEXT) unit.$(OBJEXT) unit_types.$(OBJEXT) \
video.$(OBJEXT) button.$(OBJEXT) menu.$(OBJEXT) \
textbox.$(OBJEXT) slider.$(OBJEXT)
wesnoth_editor_OBJECTS = $(am_wesnoth_editor_OBJECTS)
wesnoth_editor_LDADD = $(LDADD)
wesnoth_editor_DEPENDENCIES =
@ -397,8 +402,8 @@ am__depfiles_maybe = depfiles
@AMDEP_TRUE@ ./$(DEPDIR)/image.Po ./$(DEPDIR)/intro.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/key.Po ./$(DEPDIR)/language.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/log.Po ./$(DEPDIR)/map.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/menu.Po ./$(DEPDIR)/mouse.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/multiplayer.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/mapgen.Po ./$(DEPDIR)/menu.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/mouse.Po ./$(DEPDIR)/multiplayer.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/multiplayer_client.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/multiplayer_lobby.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/network.Po ./$(DEPDIR)/pathfind.Po \
@ -501,6 +506,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/language.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/map.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mapgen.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/menu.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mouse.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/multiplayer.Po@am__quote@

View file

@ -13,6 +13,7 @@
#include "events.hpp"
#include "font.hpp"
#include "game_config.hpp"
#include "image.hpp"
#include "key.hpp"
#include "language.hpp"
@ -38,7 +39,7 @@ void show_about(display& disp)
0,0,0,1.0,disp.video().getSurface());
update_whole_screen();
const scoped_sdl_surface map_image(image::get_image("misc/map.png",image::UNSCALED));
const scoped_sdl_surface map_image(image::get_image(game_config::map_image,image::UNSCALED));
SDL_Rect map_rect;
map_rect.x = disp.x()/2 - map_image->w/2;
map_rect.y = disp.y()/2 - map_image->h/2;
@ -97,7 +98,7 @@ void show_about(display& disp)
text.push_back("-web developer");
text.push_back("-artwork and graphics designer");
text.push_back("Joseph Toscano (zhaymusic.com)");
text.push_back("-music and sound designer");
text.push_back("-music");
text.push_back("Justin Zaun (jzaun)");
text.push_back("-developer");
text.push_back("-scenario designer");
@ -109,7 +110,9 @@ void show_about(display& disp)
text.push_back("-internationalization manager");
text.push_back("-translator");
text.push_back("Pau Congost");
text.push_back("-music and sound designer");
text.push_back("-music");
text.push_back("Fredrik Lindroth");
text.push_back("-music");
text.push_back("Slainte");
text.push_back("-artwork and graphics designer");
text.push_back("Zas");
@ -141,7 +144,7 @@ void show_about(display& disp)
int line = startline;
for(int cur_line=0;cur_line<12;cur_line++)
{
if(line>text.size()-1)
if(size_t(line) > text.size()-1)
line=0;
SDL_Rect tr = font::draw_text(&disp,disp.screen_area(),24,font::BLACK_COLOUR,
text[line], -1,height);
@ -154,7 +157,7 @@ void show_about(display& disp)
timer = 0;
startline++;
}
if(startline == text.size())
if(size_t(startline) == text.size())
startline = 0;
if(close.process(mousex,mousey,left_button)) {

View file

@ -264,14 +264,15 @@ battle_stats evaluate_battle_stats(
res.defend_special = defender_attacks[defend].special();
}
if(defender_attacks[defend].special() == drain_string) {
//if the defender drains, and the attacker is a living creature, then
//the defender will drain for half the damage it does
if(defender_attacks[defend].special() == drain_string && !a->second.type().not_living()) {
res.amount_defender_drains = res.damage_attacker_takes/2;
} else {
res.amount_defender_drains = 0;
}
res.defender_plague =
(defender_attacks[defend].special() == plague_string);
res.defender_plague = (defender_attacks[defend].special() == plague_string);
}
if(attack.special() == magical_string)
@ -291,7 +292,9 @@ battle_stats evaluate_battle_stats(
if(under_leadership(units,attacker))
res.damage_defender_takes += res.damage_defender_takes/8 + 1;
if(attack.special() == drain_string) {
//if the attacker drains, and the defender is a living creature, then
//the attacker will drain for half the damage it does
if(attack.special() == drain_string && !d->second.type().not_living()) {
res.amount_attacker_drains = res.damage_defender_takes/2;
} else {
res.amount_attacker_drains = 0;
@ -1057,6 +1060,9 @@ void clear_shroud_unit(const gamemap& map, const game_data& gamedata,
clear_shroud_loc(map,teams[team],i->first,&cleared_locations);
}
//clear the location the unit is at
clear_shroud_loc(map,teams[team],loc,&cleared_locations);
for(std::vector<gamemap::location>::const_iterator it =
cleared_locations.begin(); it != cleared_locations.end(); ++it) {
if(units.count(*it)) {

View file

@ -23,6 +23,7 @@
#include "filesystem.hpp"
#include "game_config.hpp"
#include "log.hpp"
#include "scoped_resource.hpp"
bool operator<(const line_source& a, const line_source& b)
{
@ -58,37 +59,53 @@ line_source get_line_source(const std::vector<line_source>& line_src, int line)
return res;
}
std::string read_file_internal(const std::string& fname)
struct close_FILE
{
std::ifstream file(fname.c_str());
std::string res;
char c;
while(file.get(c)) {
res.resize(res.size()+1);
res[res.size()-1] = c;
void operator()(FILE* f) const { if(f != NULL) { fclose(f); } }
};
void read_file_internal(const std::string& fname, std::string& res)
{
res.resize(0);
const util::scoped_resource<FILE*,close_FILE> file(fopen(fname.c_str(),"rb"));
if(file == NULL) {
return;
}
return res;
const int block_size = 4096;
char buf[block_size];
for(;;) {
size_t nbytes = fread(buf,1,block_size,file);
res.resize(res.size()+nbytes);
std::copy(buf,buf+nbytes,res.end()-nbytes);
if(nbytes < block_size) {
return;
}
}
}
} //end anon namespace
std::string read_file(const std::string& fname)
{
log_scope("reading file");
//if we have a path to the data,
//convert any filepath which is relative
if(!fname.empty() && fname[0] != '/' && !game_config::path.empty()) {
std::cerr << "trying to read file: '" <<
game_config::path << "/" << fname << "'\n";
const std::string& res =
read_file_internal(game_config::path + "/" + fname);
std::string res;
read_file_internal(game_config::path + "/" + fname,res);
if(!res.empty()) {
std::cerr << "success\n";
return res;
}
}
return read_file_internal(fname);
std::string res;
read_file_internal(fname,res);
return res;
}
void write_file(const std::string& fname, const std::string& data)

View file

@ -166,4 +166,15 @@ std::string load_game_dialog(display& disp, bool* show_replay)
return games[res].name;
}
void unit_speak(const config& message_info, display& disp, const unit_map& units)
{
for(unit_map::const_iterator i = units.begin(); i != units.end(); ++i) {
if(i->second.matches_filter(message_info)) {
disp.scroll_to_tile(i->first.x,i->first.y);
const scoped_sdl_surface surface(image::get_image(i->second.type().image_profile(),image::UNSCALED));
gui::show_dialog(disp,surface,i->second.underlying_description(),message_info["message"],gui::MESSAGE);
}
}
}
} //end namespace dialogs

View file

@ -14,8 +14,10 @@
#define DIALOGS_H_INCLUDED
#include "actions.hpp"
#include "config.hpp"
#include "display.hpp"
#include "show_dialog.hpp"
#include "unit.hpp"
namespace dialogs
{
@ -38,6 +40,8 @@ int get_save_name(display & disp, const std::string& caption,
//the user will not be asked if they want to show a replay.
std::string load_game_dialog(display& disp, bool* show_replay);
void unit_speak(const config& message_info, display& disp, const unit_map& units);
}
#endif

View file

@ -88,9 +88,6 @@ namespace {
const size_t Minimap_h = 146;
const size_t TimeOfDay_x = 13;
const size_t TimeOfDay_y = 167;
const std::string RightSideTop = "misc/rightside.png";
const std::string RightSideBot = "misc/rightside-bottom.png";
}
display::display(unit_map& units, CVideo& video, const gamemap& map,
@ -424,10 +421,10 @@ void display::draw(bool update,bool force)
{
if(!sideBarBgDrawn_ && !teams_.empty()) {
SDL_Surface* const screen = screen_.getSurface();
const scoped_sdl_surface image_top(image::get_image(RightSideTop,image::UNSCALED));
const scoped_sdl_surface image_top(image::get_image(game_config::rightside_image,image::UNSCALED));
const scoped_sdl_surface image(image_top != NULL ?
image::get_image_dim(RightSideBot,image_top->w,screen->h-image_top->h) : NULL);
image::get_image_dim(game_config::rightside_image_bot,image_top->w,screen->h-image_top->h) : NULL);
if(image_top != NULL && image != NULL && image_top->h < screen->h) {
SDL_Rect dstrect;
@ -553,7 +550,7 @@ void display::draw_game_status(int x, int y)
if(gameStatusRect_.w > 0) {
SDL_Surface* const screen = screen_.getSurface();
const scoped_sdl_surface background(image::get_image(RightSideTop,image::UNSCALED));
const scoped_sdl_surface background(image::get_image(game_config::rightside_image,image::UNSCALED));
if(background == NULL)
return;
@ -615,8 +612,7 @@ void display::draw_game_status(int x, int y)
}
if(unit_selected != units_.end() && map_.on_board(mouseoverHex_)) {
const gamemap::TERRAIN terrain =
map_[mouseoverHex_.x][mouseoverHex_.y];
const gamemap::TERRAIN terrain = map_[mouseoverHex_.x][mouseoverHex_.y];
const unit& u = unit_selected->second;
const int move_cost = u.movement_cost(map_,terrain);
@ -653,8 +649,8 @@ void display::draw_unit_details(int x, int y, const gamemap::location& loc,
SDL_Rect clipRect = clip_rect != NULL ? *clip_rect : screen_area();
const scoped_sdl_surface background(image::get_image(RightSideTop,image::UNSCALED));
const scoped_sdl_surface background_bot(image::get_image(RightSideBot,image::UNSCALED));
const scoped_sdl_surface background(image::get_image(game_config::rightside_image,image::UNSCALED));
const scoped_sdl_surface background_bot(image::get_image(game_config::rightside_image_bot,image::UNSCALED));
if(background == NULL || background_bot == NULL)
return;
@ -914,8 +910,8 @@ void display::draw_tile(int x, int y, SDL_Surface* unit_image_override,
const bool is_shrouded = shrouded(x,y);
gamemap::TERRAIN terrain = gamemap::VOID_TERRAIN;
if(map_.on_board(loc) && !is_shrouded) {
terrain = map_[x][y];
if(!is_shrouded) {
terrain = map_.get_terrain(loc);
}
image::TYPE image_type = image::SCALED;
@ -1020,26 +1016,37 @@ void display::draw_tile(int x, int y, SDL_Surface* unit_image_override,
const int unit_move = it->second.movement_left();
const int unit_total_move = it->second.total_movement();
const char* energy_file = NULL;
const std::string* energy_file = NULL;
if(size_t(it->second.side()) != currentTeam_+1) {
if(team_valid() &&
teams_[currentTeam_].is_enemy(it->second.side())) {
energy_file = "enemy-energy.png";
energy_file = &game_config::enemy_energy_image;
} else {
energy_file = "ally-energy.png";
energy_file = &game_config::ally_energy_image;
}
} else {
if(activeTeam_ == currentTeam_ && unit_move == unit_total_move) {
energy_file = "unmoved-energy.png";
energy_file = &game_config::unmoved_energy_image;
} else if(activeTeam_ == currentTeam_ && unit_can_move(loc,units_,map_,teams_)) {
energy_file = "partmoved-energy.png";
energy_file = &game_config::partmoved_energy_image;
} else {
energy_file = "moved-energy.png";
energy_file = &game_config::moved_energy_image;
}
}
energy_image.assign(image::get_image(energy_file));
assert(energy_file != NULL);
if(energy_file == NULL) {
std::cerr << "energy file is NULL\n";
return;
}
energy_image.assign(image::get_image(*energy_file));
if(energy_image.get() == NULL) {
std::cerr << "failed to get energy image: '" << *energy_file << "'\n";
return;
}
unit_energy = double(it->second.hitpoints()) /
double(it->second.max_hitpoints());
@ -1215,7 +1222,7 @@ void display::draw_tile(int x, int y, SDL_Surface* unit_image_override,
}
if(game_config::debug && debugHighlights_.count(gamemap::location(x,y))) {
const scoped_sdl_surface cross(image::get_image("cross.png"));
const scoped_sdl_surface cross(image::get_image(game_config::cross_image));
if(cross != NULL)
draw_unit(xpos-xsrc,ypos-ysrc,cross,face_left,false,
debugHighlights_[loc],0);
@ -1240,8 +1247,11 @@ void display::draw_tile(int x, int y, SDL_Surface* unit_image_override,
highlight_ratio = advancingAmount_;
}
draw_unit(xpos-xsrc,ypos-ysrc,unit_image,face_left,false,
highlight_ratio,blend_with);
const int height_adjust = it->second.is_flying() ? 0 : map_.get_terrain_info(terrain).unit_height_adjust()*(zoom_/DefaultZoom);
const double submerge = it->second.is_flying() ? 0.0 : map_.get_terrain_info(terrain).unit_submerge();
draw_unit(xpos-xsrc,ypos-ysrc - height_adjust,unit_image,face_left,false,
highlight_ratio,blend_with,submerge);
}
const bool energy_uses_alpha = highlight_ratio < 1.0 && blend_with == 0;
@ -1336,10 +1346,10 @@ void display::draw_footstep(const gamemap::location& loc, int xloc, int yloc)
}
}
static const std::string left_nw("misc/foot-left-nw.png");
static const std::string left_n("misc/foot-left-n.png");
static const std::string right_nw("misc/foot-right-nw.png");
static const std::string right_n("misc/foot-right-n.png");
static const std::string left_nw(game_config::foot_left_nw);
static const std::string left_n(game_config::foot_left_n);
static const std::string right_nw(game_config::foot_right_nw);
static const std::string right_n(game_config::foot_right_n);
const std::string* image_str = &left_nw;
@ -1408,19 +1418,16 @@ std::vector<SDL_Surface*> display::getAdjacentTerrain(int x, int y,
std::vector<SDL_Surface*> res;
gamemap::location loc(x,y);
const gamemap::TERRAIN current_terrain = map_.on_board(loc) ? map_[x][y]:0;
const gamemap::TERRAIN current_terrain = map_.get_terrain(loc);
gamemap::location adjacent[6];
get_adjacent_tiles(loc,adjacent);
int tiles[6];
for(int i = 0; i != 6; ++i) {
tiles[i] = map_.on_board(adjacent[i]) ?
(int)map_[adjacent[i].x][adjacent[i].y] :
(int)gamemap::VOID_TERRAIN;
tiles[i] = map_.get_terrain(adjacent[i]);
}
const std::vector<gamemap::TERRAIN>& precedence =
map_.get_terrain_precedence();
const std::vector<gamemap::TERRAIN>& precedence = map_.get_terrain_precedence();
std::vector<gamemap::TERRAIN>::const_iterator terrain =
std::find(precedence.begin(),precedence.end(),current_terrain);
@ -1485,11 +1492,6 @@ SDL_Surface* display::getTerrain(gamemap::TERRAIN terrain,image::TYPE image_type
map_.get_terrain_info(terrain).image(x,y) :
map_.get_terrain_info(terrain).adjacent_image());
if(terrain == gamemap::CASTLE &&
map_.is_starting_position(gamemap::location(x,y)) != -1) {
image = "terrain/keep";
}
//see if there is a time-of-day specific version of this image
if(direction == "") {
const time_of_day& tod = status_.get_time_of_day();
@ -1646,10 +1648,9 @@ double display::get_location_x(const gamemap::location& loc) const
double display::get_location_y(const gamemap::location& loc) const
{
return static_cast<double>(loc.y)*zoom_ - ypos_ +
((loc.x % 2) == 1 ? zoom_/2.0 : 0.0);
(is_odd(loc.x) ? zoom_/2.0 : 0.0);
}
bool display::unit_attack_ranged(const gamemap::location& a,
const gamemap::location& b, int damage,
const attack_type& attack)
@ -1771,8 +1772,8 @@ bool display::unit_attack_ranged(const gamemap::location& a,
= attack.get_frame(missile_frame,NULL,
attack_type::MISSILE_FRAME,dir);
static const std::string default_missile("missile-n.png");
static const std::string default_diag_missile("missile-ne.png");
static const std::string default_missile(game_config::missile_n_image);
static const std::string default_diag_missile(game_config::missile_ne_image);
if(missile_image == NULL) {
if(dir == attack_type::VERTICAL)
missile_image = &default_missile;
@ -1940,6 +1941,15 @@ bool display::unit_attack(const gamemap::location& a,
hiddenUnit_ = a;
const gamemap::TERRAIN src_terrain = map_.get_terrain(a);
const gamemap::TERRAIN dst_terrain = map_.get_terrain(b);
const double src_height_adjust = attacker.is_flying() ? 0 : map_.get_terrain_info(src_terrain).unit_height_adjust() * (zoom_/DefaultZoom);
const double dst_height_adjust = attacker.is_flying() ? 0 : map_.get_terrain_info(dst_terrain).unit_height_adjust() * (zoom_/DefaultZoom);
const double src_submerge = attacker.is_flying() ? 0 : map_.get_terrain_info(src_terrain).unit_submerge();
const double dst_submerge = attacker.is_flying() ? 0 : map_.get_terrain_info(dst_terrain).unit_submerge();
for(int i = begin_at; i < end_at; i += time_resolution*acceleration) {
events::pump();
@ -2000,8 +2010,11 @@ bool display::unit_attack(const gamemap::location& a,
const int posx = int(pos*xsrc + (1.0-pos)*xdst) + xoffset;
const int posy = int(pos*ysrc + (1.0-pos)*ydst);
const int height_adjust = int(src_height_adjust*pos + dst_height_adjust*(1.0-pos));
const double submerge = src_submerge*pos + dst_submerge*(1.0-pos);
if(image != NULL && !hide)
draw_unit(posx,posy,image,attacker.facing_left());
draw_unit(posx,posy-height_adjust,image,attacker.facing_left(),false,1.0,0,submerge);
const int wait_time = ticks + time_resolution - SDL_GetTicks();
if(wait_time > 0 && !hide)
@ -2040,6 +2053,15 @@ void display::move_unit_between(const gamemap::location& a,
double xdst = get_location_x(b);
double ydst = get_location_y(b);
const gamemap::TERRAIN src_terrain = map_.get_terrain(a);
const gamemap::TERRAIN dst_terrain = map_.get_terrain(b);
const int src_height_adjust = u.is_flying() ? 0 : map_.get_terrain_info(src_terrain).unit_height_adjust() * (zoom_/DefaultZoom);
const int dst_height_adjust = u.is_flying() ? 0 : map_.get_terrain_info(dst_terrain).unit_height_adjust() * (zoom_/DefaultZoom);
const double src_submerge = u.is_flying() ? 0 : map_.get_terrain_info(src_terrain).unit_submerge();
const double dst_submerge = u.is_flying() ? 0 : map_.get_terrain_info(dst_terrain).unit_submerge();
const double nsteps = turbo() ? 3.0 : 10.0;
const double xstep = (xdst - xsrc)/nsteps;
const double ystep = (ydst - ysrc)/nsteps;
@ -2110,8 +2132,11 @@ void display::move_unit_between(const gamemap::location& a,
draw_tile(adjacent[tile].x,adjacent[tile].y);
}
const int height_adjust = src_height_adjust + (dst_height_adjust-src_height_adjust)*(i/nsteps);
const double submerge = src_submerge + (dst_submerge-src_submerge)*(i/nsteps);
draw(false);
draw_unit((int)xloc,(int)yloc,image,face_left);
draw_unit((int)xloc,(int)yloc - height_adjust,image,face_left,false,1.0,0,submerge);
const int new_ticks = SDL_GetTicks();
const int wait_time = time_between_frames - (new_ticks - ticks);
@ -2132,8 +2157,11 @@ void display::move_unit_between(const gamemap::location& a,
void display::draw_unit(int x, int y, SDL_Surface* image,
bool reverse, bool upside_down,
double alpha, Pixel blendto)
double alpha, Pixel blendto, double submerged)
{
//the alpha value to use for submerged units
static const double unit_submerged_alpha = 0.2;
if(updatesLocked_) {
return;
}
@ -2150,7 +2178,10 @@ void display::draw_unit(int x, int y, SDL_Surface* image,
surface_lock srclock(image);
const Pixel* src = srclock.pixels();
const int endy = (y + image->h) < h ? (y + image->h) : h;
const int height = image->h; //*(1.0 - submerged);
const int submerge_height = y + image->h*(1.0 - submerged);
const int endy = (y + height) < h ? (y + height) : h;
const int endx = (x + image->w) < w ? (x + image->w) : w;
if(endx < x)
return;
@ -2191,6 +2222,11 @@ void display::draw_unit(int x, int y, SDL_Surface* image,
for(; y != endy; ++y, src += src_increment) {
Pixel* dst = screen_lock.pixels() + y*screen->w + x;
if(y == submerge_height && alpha > unit_submerged_alpha) {
alpha = unit_submerged_alpha;
blendto = 0;
}
if(alpha == 1.0) {
if(reverse) {
for(int i = xoffset; i != len; ++i) {
@ -2249,7 +2285,7 @@ const std::pair<int,int>& display::calculate_energy_bar()
int first_row = -1;
int last_row = -1;
const scoped_sdl_surface image(image::get_image("unmoved-energy.png"));
const scoped_sdl_surface image(image::get_image(game_config::unmoved_energy_image));
surface_lock image_lock(image);
const short* const begin = image_lock.pixels();
@ -2273,7 +2309,7 @@ const std::pair<int,int>& display::calculate_energy_bar()
void display::invalidate(const gamemap::location& loc)
{
if(!invalidateAll_ && loc.valid()) {
if(!invalidateAll_) {
invalidated_.insert(loc);
}
}
@ -2313,6 +2349,16 @@ void display::remove_overlay(const gamemap::location& loc)
overlays_.erase(loc);
}
void display::write_overlays(config& cfg) const
{
for(std::multimap<gamemap::location,std::string>::const_iterator i = overlays_.begin();
i != overlays_.end(); ++i) {
config& item = cfg.add_child("item");
i->first.write(item);
item["image"] = i->second;
}
}
void display::set_team(size_t team)
{
assert(team < teams_.size());
@ -2401,3 +2447,8 @@ size_t display::viewing_team() const
{
return currentTeam_;
}
size_t display::playing_team() const
{
return activeTeam_;
}

View file

@ -193,6 +193,9 @@ public:
void add_overlay(const gamemap::location& loc, const std::string& image);
void remove_overlay(const gamemap::location& loc);
//function to serialize overlay data
void write_overlays(config& cfg) const;
//function which draws the details of the unit at the given location, at
//(x,y) on-screen. xprofile and yprofile are the size of the unit's image.
//this function is suitable for drawing a unit's details on the sidebar,
@ -247,7 +250,10 @@ public:
bool fogged(int x, int y) const;
//the viewing team is the team currently viewing the game. The playing team
//is the team whose turn it is
size_t viewing_team() const;
size_t playing_team() const;
private:
display(const display&);
@ -257,9 +263,19 @@ private:
const gamemap::location& b,
const unit& u);
//function to draw the image of a unit at a certain location
//x,y: pixel location on screen to draw the unit
//image: the image of the unit
//reverse: if the unit should be flipped across the y axis
//upside_down: if the unit should be flipped across the x axis
//alpha: the merging to use with the background
//blendto: if blendto is not 0, then the alpha parameter will be used
// to blend to this colour, instead of the background
//submerged: the amount of the unit out of 1.0 that is submerged
// (presumably under water) and thus shouldn't be drawn
void draw_unit(int x, int y, SDL_Surface* image,
bool reverse, bool upside_down=false,
double alpha=1.0, short blendto=0);
double alpha=1.0, short blendto=0, double submerged=0.0);
void unit_die(const gamemap::location& loc, SDL_Surface* image=NULL);

View file

@ -6,6 +6,7 @@
#include <algorithm>
#include <cassert>
#include <stack>
#include <utility>
#include <vector>
@ -26,22 +27,50 @@ resize_lock::~resize_lock()
--disallow_resize;
}
std::vector<handler*> event_handlers;
//this object stores all the event handlers. It is a stack of event 'contexts'.
//a new event context is created when e.g. a modal dialog is opened, and then
//closed when that dialog is closed. Each context contains a list of the handlers
//in that context. The current context is the one on the top of the stack
std::stack<std::vector<handler*> > event_contexts;
event_context::event_context()
{
event_contexts.push(std::vector<handler*>());
}
event_context::~event_context()
{
assert(event_contexts.empty() == false);
assert(event_contexts.top().empty());
event_contexts.pop();
}
handler::handler() : unicode_(SDL_EnableUNICODE(1))
{
SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY,SDL_DEFAULT_REPEAT_INTERVAL);
event_handlers.push_back(this);
event_contexts.top().push_back(this);
}
handler::~handler()
{
assert(!event_handlers.empty());
if(event_handlers.back() == this) {
event_handlers.pop_back();
assert(event_contexts.empty() == false);
std::vector<handler*>& handlers = event_contexts.top();
assert(handlers.empty() == false);
//the handler is most likely on the back of the events array,
//so look there first, otherwise do a complete search.
if(handlers.back() == this) {
handlers.pop_back();
} else {
event_handlers.erase(std::find(event_handlers.begin(),
event_handlers.end(),this));
const std::vector<handler*>::iterator i = std::find(handlers.begin(),handlers.end(),this);
if(i != handlers.end()) {
handlers.erase(i);
} else {
std::cerr << "CRITICAL ERROR: Could not find event handler in events array\n";
}
}
SDL_EnableUNICODE(unicode_);
@ -59,16 +88,20 @@ void pump()
SDL_Event event;
while(SDL_PollEvent(&event)) {
//events may cause more event handlers to be added and/or removed,
//so we must use indexes instead of iterators here.
for(size_t i1 = 0, i2 = event_handlers.size(); i1 != i2 && i1 < event_handlers.size(); ++i1) {
event_handlers[i1]->handle_event(event);
if(event_contexts.empty() == false) {
const std::vector<handler*>& event_handlers = event_contexts.top();
//events may cause more event handlers to be added and/or removed,
//so we must use indexes instead of iterators here.
for(size_t i1 = 0, i2 = event_handlers.size(); i1 != i2 && i1 < event_handlers.size(); ++i1) {
event_handlers[i1]->handle_event(event);
}
}
switch(event.type) {
case SDL_VIDEORESIZE: {
const SDL_ResizeEvent* const resize
= reinterpret_cast<SDL_ResizeEvent*>(&event);
const SDL_ResizeEvent* const resize = reinterpret_cast<SDL_ResizeEvent*>(&event);
if(resize->w < 800 || resize->h < 600) {
resize_dimensions.first = 0;
@ -127,4 +160,32 @@ void pump()
}
}
void raise_process_event()
{
if(event_contexts.empty() == false) {
const std::vector<handler*>& event_handlers = event_contexts.top();
//events may cause more event handlers to be added and/or removed,
//so we must use indexes instead of iterators here.
for(size_t i1 = 0, i2 = event_handlers.size(); i1 != i2 && i1 < event_handlers.size(); ++i1) {
event_handlers[i1]->process();
}
}
}
void raise_draw_event()
{
if(event_contexts.empty() == false) {
const std::vector<handler*>& event_handlers = event_contexts.top();
//events may cause more event handlers to be added and/or removed,
//so we must use indexes instead of iterators here.
for(size_t i1 = 0, i2 = event_handlers.size(); i1 != i2 && i1 < event_handlers.size(); ++i1) {
event_handlers[i1]->draw();
}
}
}
}

View file

@ -17,14 +17,18 @@ struct resize_lock {
};
//any classes that derive from this class will automatically
//receive sdl events through the handle function for their lifetime
//note that handlers should *always* be allocated as automatic variables
//(never on the free store or in static memory), as the event mechanism
//relies on handlers being created and destroyed in LIFO ordering.
//receive sdl events through the handle function for their lifetime,
//while the event context they were created in is active.
//
//NOTE: an event_context object must be initialized before a handler object
//can be initialized, and the event_context must be destroyed after
//the handler is destroyed.
class handler
{
public:
virtual void handle_event(const SDL_Event& event) = 0;
virtual void process() {}
virtual void draw() const {}
protected:
handler();
virtual ~handler();
@ -33,8 +37,26 @@ private:
const int unicode_;
};
//event_context objects control the handler objects that SDL events are sent
//to. When an event_context is created, it will become the current event context.
//event_context objects MUST be created in LIFO ordering in relation to each other,
//and in relation to handler objects. That is, all event_context objects should be
//created as automatic/stack variables.
//
//handler objects need not be created as automatic variables (e.g. you could put
//them in a vector) however you must guarantee that handler objects are destroyed
//before their context is destroyed
struct event_context
{
event_context();
~event_context();
};
//causes events to be dispatched to all handler objects.
void pump();
void raise_process_event();
void raise_draw_event();
}
#endif

View file

@ -229,7 +229,10 @@ bool is_directory_internal(const std::string& fname)
#else
struct stat dir_stat;
::stat(fname.c_str(), &dir_stat);
if(::stat(fname.c_str(), &dir_stat) == -1) {
return false;
}
return S_ISDIR(dir_stat.st_mode);
#endif
}
@ -258,6 +261,8 @@ bool file_exists(const std::string& name)
time_t file_create_time(const std::string& fname)
{
struct stat buf;
::stat(fname.c_str(),&buf);
if(::stat(fname.c_str(),&buf) == -1)
return 0;
return buf.st_mtime;
}

View file

@ -19,6 +19,7 @@
#include "config.hpp"
#include "dialogs.hpp"
#include "display.hpp"
#include "events.hpp"
#include "filesystem.hpp"
#include "font.hpp"
#include "game_config.hpp"
@ -26,6 +27,7 @@
#include "gamestatus.hpp"
#include "key.hpp"
#include "language.hpp"
#include "mapgen.hpp"
#include "multiplayer.hpp"
#include "multiplayer_client.hpp"
#include "network.hpp"
@ -55,7 +57,22 @@ LEVEL_RESULT play_game(display& disp, game_state& state, config& game_config,
if(type.empty())
type = "scenario";
config* scenario = game_config.find_child(type,"id",state.scenario);
config* scenario = NULL;
config starting_pos;
//see if we load the scenario from the scenario data -- if there is
//no snapshot data available from a save, or if the user has selected
//to view the replay from scratch
if(state.starting_pos.child("side") == NULL || !recorder.at_end()) {
scenario = game_config.find_child(type,"id",state.scenario);
} else {
//load from a save-snapshot.
starting_pos = state.starting_pos;
scenario = &starting_pos;
state = read_game(units_data,&state.starting_pos);
}
while(scenario != NULL) {
const config::child_list& story = scenario->get_children("story");
@ -78,6 +95,8 @@ LEVEL_RESULT play_game(display& disp, game_state& state, config& game_config,
video,state,story);
}
state.starting_pos = config();
//ask to save a replay of the game
if(res == VICTORY || res == DEFEAT) {
const std::string orig_scenario = state.scenario;
@ -90,7 +109,8 @@ LEVEL_RESULT play_game(display& disp, game_state& state, config& game_config,
string_table["save_game_label"],
&label);
if(should_save == 0) {
recorder.save_game(units_data,label);
config starting_pos;
recorder.save_game(units_data,label,starting_pos);
}
state.scenario = orig_scenario;
@ -103,13 +123,16 @@ LEVEL_RESULT play_game(display& disp, game_state& state, config& game_config,
return res;
}
} catch(gamestatus::load_game_failed& e) {
gui::show_dialog(disp,NULL,"","The game could not be loaded: " + e.message,gui::OK_ONLY);
std::cerr << "The game could not be loaded: " << e.message << "\n";
return QUIT;
} catch(gamestatus::game_error& e) {
gui::show_dialog(disp,NULL,"","An error occurred while playing the game: " + e.message,gui::OK_ONLY);
std::cerr << "An error occurred while playing the game: "
<< e.message << "\n";
return QUIT;
} catch(gamemap::incorrect_format_exception& e) {
gui::show_dialog(disp,NULL,"",e.msg_,gui::OK_ONLY);
std::cerr << "The game map could not be loaded: " << e.msg_ << "\n";
return QUIT;
}
@ -145,11 +168,14 @@ LEVEL_RESULT play_game(display& disp, game_state& state, config& game_config,
int play_game(int argc, char** argv)
{
srand(time(NULL));
CVideo video;
const font::manager font_manager;
const sound::manager sound_manager;
const preferences::manager prefs_manager;
const image::manager image_manager;
const events::event_context main_event_context;
bool test_mode = false;
@ -197,14 +223,17 @@ int play_game(int argc, char** argv)
defines_map["NORMAL"] = preproc_define();
std::vector<line_source> line_src;
std::string game_cfg = preprocess_file("data/game.cfg",&defines_map,
&line_src);
std::string game_cfg = preprocess_file("data/game.cfg",&defines_map,&line_src);
config game_config(game_cfg,&line_src);
//clear game_cfg so it doesn't take up memory
std::string().swap(game_cfg);
game_config::load_config(game_config.child("game_config"));
const map_generator::manager map_generation_manager(game_config);
const config::child_list& units = game_config.get_children("units");
if(units.empty()) {
std::cerr << "Could not find units configuration\n";
@ -296,7 +325,7 @@ int play_game(int argc, char** argv)
SDL_WM_SetCaption(string_table["game_title"].c_str(), NULL);
for(;;) {
sound::play_music("wesnoth-1.ogg");
sound::play_music(game_config::title_music);
game_state state;
@ -313,11 +342,12 @@ int play_game(int argc, char** argv)
return 0;
}
recorder.clear();
gui::TITLE_RESULT res = gui::show_title(disp);
if(res == gui::QUIT_GAME) {
return 0;
} else if(res == gui::LOAD_GAME) {
srand(SDL_GetTicks());
bool show_replay;
@ -352,7 +382,14 @@ int play_game(int argc, char** argv)
}
recorder = replay(state.replay_data);
if(!recorder.empty()) {
//only play replay data if the user has selected to view the replay,
//or if there is no starting position data to use.
if(!show_replay && state.starting_pos.child("side") == NULL) {
recorder.set_to_end();
}
if(!recorder.at_end()) {
//set whether the replay is to be skipped or not
if(show_replay) {
recorder.set_skip(0);
@ -450,15 +487,20 @@ int play_game(int argc, char** argv)
play_multiplayer_client(disp,units_data,game_config,state);
}
} catch(gamestatus::load_game_failed& e) {
std::cerr << "error loading the game: " << e.message
<< "\n";
gui::show_dialog(disp,NULL,"","error loading the game: " + e.message,gui::OK_ONLY);
std::cerr << "error loading the game: " << e.message << "\n";
return 0;
} catch(gamestatus::game_error& e) {
gui::show_dialog(disp,NULL,"","error while playing the game: " + e.message,gui::OK_ONLY);
std::cerr << "error while playing the game: "
<< e.message << "\n";
return 0;
} catch(network::error& e) {
gui::show_dialog(disp,NULL,"",e.message,gui::OK_ONLY);
} catch(gamemap::incorrect_format_exception& e) {
gui::show_dialog(disp,NULL,"",std::string("The game map could not be loaded: ") + e.msg_,gui::OK_ONLY);
std::cerr << "The game map could not be loaded: " << e.msg_ << "\n";
continue;
}
continue;
@ -476,6 +518,7 @@ int play_game(int argc, char** argv)
} else if(res == gui::EDIT_PREFERENCES) {
const preferences::display_manager disp_manager(&disp);
preferences::show_preferences_dialog(disp);
disp.redraw_everything();
continue;
} else if(res == gui::SHOW_ABOUT) {

View file

@ -12,23 +12,85 @@
*/
#include "game_config.hpp"
#include <cstdlib>
namespace game_config
{
const int unit_cost = 1;
const int base_income = 2;
const int tower_income = 1;
const int heal_amount = 4;
const int healer_heals_per_turn = 8;
const int cure_amount = 8;
const int curer_heals_per_turn = 18;
const int recall_cost = 20;
const int kill_experience = 8;
const std::string version = "0.6.1";
int base_income = 2;
int tower_income = 1;
int heal_amount = 4;
int healer_heals_per_turn = 8;
int cure_amount = 8;
int curer_heals_per_turn = 18;
int recall_cost = 20;
int kill_experience = 8;
const std::string version = "0.6.2-CVS";
bool debug = false;
std::string game_icon, game_title, title_music;
std::string missile_n_image, missile_ne_image;
std::string map_image = "misc/map.png";
std::string rightside_image = "misc/rightside.png";
std::string rightside_image_bot = "misc/rightside-bottom.png";
std::string moved_energy_image = "moved-energy.png";
std::string unmoved_energy_image = "unmoved-energy.png";
std::string partmoved_energy_image = "partmoved-energy.png";
std::string enemy_energy_image = "enemy-energy.png";
std::string ally_energy_image = "ally-energy.png";
std::string dot_image = "misc/dot.png";
std::string cross_image = "misc/cross.png";
std::string foot_left_nw, foot_left_n, foot_right_nw, foot_right_n;
#ifdef WESNOTH_PATH
std::string path = WESNOTH_PATH;
#else
std::string path = "";
#endif
void load_config(const config* cfg)
{
if(cfg == NULL)
return;
const config& v = *cfg;
base_income = atoi(v["base_income"].c_str());
tower_income = atoi(v["village_income"].c_str());
heal_amount = atoi(v["heal_amount"].c_str());
healer_heals_per_turn = atoi(v["healer_heals_per_turn"].c_str());
cure_amount = atoi(v["cure_amount"].c_str());
curer_heals_per_turn = atoi(v["curer_heals_per_turn"].c_str());
recall_cost = atoi(v["recall_cost"].c_str());
kill_experience = atoi(v["kill_experience"].c_str());
game_icon = v["icon"];
game_title = v["title"];
title_music = v["title_music"];
map_image = v["map_image"];
rightside_image = v["sidebar_image"];
rightside_image_bot = v["sidebar_image_bottom"];
moved_energy_image = v["moved_energy_image"];
unmoved_energy_image = v["unmoved_energy_image"];
partmoved_energy_image = v["partmoved_energy_image"];
enemy_energy_image = v["enemy_energy_image"];
ally_energy_image = v["ally_energy_image"];
cross_image = v["cross_image"];
dot_image = v["dot_image"];
foot_left_nw = v["footprint_left_nw"];
foot_left_n = v["footprint_left_n"];
foot_right_nw = v["footprint_right_nw"];
foot_right_n = v["footprint_right_n"];
missile_n_image = v["missile_n_image"];
missile_ne_image = v["missile_ne_image"];
}
}

View file

@ -13,25 +13,35 @@
#ifndef GAME_CONFIG_H_INCLUDED
#define GAME_CONFIG_H_INCLUDED
#include "config.hpp"
#include <string>
//basic game configuration information is here.
namespace game_config
{
extern const int unit_cost;
extern const int base_income;
extern const int tower_income;
extern const int heal_amount;
extern const int healer_heals_per_turn;
extern const int cure_amount;
extern const int curer_heals_per_turn;
extern const int recall_cost;
extern const int kill_experience;
extern int base_income;
extern int tower_income;
extern int heal_amount;
extern int healer_heals_per_turn;
extern int cure_amount;
extern int curer_heals_per_turn;
extern int recall_cost;
extern int kill_experience;
extern const std::string version;
extern bool debug;
extern std::string path;
extern std::string game_icon, game_title, title_music, map_image, rightside_image, rightside_image_bot,
moved_energy_image, unmoved_energy_image, partmoved_energy_image,
enemy_energy_image,ally_energy_image,
dot_image,cross_image,
foot_left_nw,foot_left_n,foot_right_nw,foot_right_n,
missile_n_image,missile_ne_image;
void load_config(const config* cfg);
}
#endif

View file

@ -162,6 +162,13 @@ public:
cfg_(cfg)
{}
void write(config& cfg) const {
if(cfg_ == NULL || disabled_)
return;
cfg = *cfg_;
}
const std::string& name() const { return name_; }
bool first_time_only() const { return first_time_only_; }
@ -914,6 +921,35 @@ manager::manager(config& cfg, display& gui_, gamemap& map_,
game_data_ptr = &game_data_;
used_items.clear();
const std::string& used = cfg["used_items"];
if(!used.empty()) {
const std::vector<std::string>& v = config::split(used);
for(std::vector<std::string>::const_iterator i = v.begin(); i != v.end(); ++i) {
used_items.insert(*i);
}
}
}
void write_events(config& cfg)
{
for(std::multimap<std::string,event_handler>::const_iterator i = events_map.begin(); i != events_map.end(); ++i) {
if(!i->second.disabled()) {
i->second.write(cfg.add_child("event"));
}
}
std::stringstream used;
for(std::set<std::string>::const_iterator u = used_items.begin(); u != used_items.end(); ++u) {
if(u != used_items.begin())
used << ",";
used << *u;
}
cfg["used_items"] = used.str();
if(screen != NULL)
screen->write_overlays(cfg);
}
manager::~manager() {

View file

@ -49,6 +49,8 @@ struct manager {
~manager();
};
void write_events(config& cfg);
//function to fire an event. Events may have up to two arguments, both of
//which must be locations.
bool fire(const std::string& event,

View file

@ -33,9 +33,34 @@ time_of_day::time_of_day(const config& cfg)
name = lang_name;
}
void time_of_day::write(config& cfg) const
{
char buf[50];
sprintf(buf,"%d",lawful_bonus);
cfg["lawful_bonus"] = buf;
sprintf(buf,"%d",red);
cfg["red"] = buf;
sprintf(buf,"%d",green);
cfg["green"] = buf;
sprintf(buf,"%d",blue);
cfg["blue"] = buf;
cfg["image"] = image;
cfg["name"] = name;
cfg["id"] = id;
}
gamestatus::gamestatus(config& time_cfg, int num_turns) :
turn_(1),numTurns_(num_turns)
{
const std::string& turn_at = time_cfg["turn_at"];
if(turn_at.empty() == false) {
turn_ = atoi(turn_at.c_str());
}
const config::child_list& times = time_cfg.get_children("time");
config::child_list::const_iterator t;
for(t = times.begin(); t != times.end(); ++t) {
@ -50,6 +75,25 @@ gamestatus::gamestatus(config& time_cfg, int num_turns) :
}
}
void gamestatus::write(config& cfg) const
{
char buf[50];
sprintf(buf,"%d",turn_);
cfg["turn_at"] = buf;
sprintf(buf,"%d",numTurns_);
cfg["turns"] = buf;
std::vector<time_of_day>::const_iterator t;
for(t = times_.begin(); t != times_.end(); ++t) {
t->write(cfg.add_child("time"));
}
for(t = illuminatedTimes_.begin(); t != illuminatedTimes_.end(); ++t) {
t->write(cfg.add_child("illuminated_time"));
}
}
const time_of_day& gamestatus::get_time_of_day(bool illuminated) const
{
if(illuminated && illuminatedTimes_.empty() == false) {
@ -79,7 +123,7 @@ bool gamestatus::next_turn()
return turn_ <= numTurns_;
}
game_state read_game(game_data& data, config* cfg)
game_state read_game(game_data& data, const config* cfg)
{
log_scope("read_game");
game_state res;
@ -151,7 +195,7 @@ void write_game(const game_state& game, config& cfg)
cfg.add_child("unit",new_cfg);
}
if(game.replay_data.children.empty() == false) {
if(game.replay_data.child("replay") == NULL) {
cfg.add_child("replay",game.replay_data);
}

View file

@ -25,6 +25,7 @@
struct time_of_day
{
explicit time_of_day(const config& cfg);
void write(config& cfg) const;
//the % bonus lawful units receive. chaotic units will
//receive -lawful_bonus.
@ -46,6 +47,7 @@ class gamestatus
{
public:
gamestatus(config& time_cfg, int num_turns);
void write(config& cfg) const;
const time_of_day& get_time_of_day(bool illuminated=false) const;
size_t turn() const;
@ -113,6 +115,9 @@ struct save_info {
//function to get a list of available saves.
std::vector<save_info> get_saves_list();
game_state read_game(game_data& data, const config* cfg);
void write_game(const game_state& game, config& cfg);
// function returns true iff there is already savegame with that name
bool save_game_exists(const std::string & name);

View file

@ -134,8 +134,7 @@ manager::~manager()
void set_wm_icon()
{
//this code seems to only display the top part of the icon in Windows XP
scoped_sdl_surface icon(get_image("icon.png",UNSCALED));
scoped_sdl_surface icon(get_image(game_config::game_icon,UNSCALED));
if(icon != NULL) {
std::cerr << "setting icon...\n";
::SDL_WM_SetIcon(icon,NULL);

View file

@ -13,11 +13,13 @@
#include "events.hpp"
#include "font.hpp"
#include "game_config.hpp"
#include "image.hpp"
#include "intro.hpp"
#include "key.hpp"
#include "language.hpp"
#include "show_dialog.hpp"
#include "sound.hpp"
#include "util.hpp"
#include "video.hpp"
#include "widgets/button.hpp"
@ -45,6 +47,11 @@ void show_intro(display& screen, const config& data)
skip_button.set_x(screen.x()-200);
skip_button.set_y(screen.y()-100);
const std::string& music = data["music"];
if(music != "") {
sound::play_music(music);
}
const config::child_list& parts = data.get_children("part");
for(config::child_list::const_iterator i = parts.begin(); i != parts.end(); ++i){
@ -192,9 +199,12 @@ void show_map_scene(display& screen, config& data)
const std::string& image_file = cfg["image"];
const scoped_sdl_surface image(image::get_image(image_file,image::UNSCALED));
const scoped_sdl_surface dot_image(image::get_image("misc/dot.png",image::UNSCALED));
const scoped_sdl_surface cross_image(image::get_image("misc/cross.png",image::UNSCALED));
const scoped_sdl_surface dot_image(image::get_image(game_config::dot_image,image::UNSCALED));
const scoped_sdl_surface cross_image(image::get_image(game_config::cross_image,image::UNSCALED));
if(image == NULL || dot_image == NULL || cross_image == NULL) {
std::cerr << "could not find map image: '" << image_file << "': " << (image == NULL ? "failed" : "ok") << "\n"
<< "'" << game_config::dot_image << "': " << (dot_image == NULL ? "failed" : "ok") << "\n"
<< "'" << game_config::cross_image << "': " << (cross_image == NULL ? "failed" : "ok") << "\n";
return;
}

View file

@ -12,6 +12,7 @@
*/
#include "game.hpp"
#include "map.hpp"
#include "pathfind.hpp"
#include "util.hpp"
#include <algorithm>
@ -78,6 +79,15 @@ gamemap::location::location(const config& cfg) : x(-1), y(-1)
y = atoi(ystr.c_str()) - 1;
}
void gamemap::location::write(config& cfg) const
{
char buf[50];
sprintf(buf,"%d",x+1);
cfg["x"] = buf;
sprintf(buf,"%d",y+1);
cfg["y"] = buf;
}
bool gamemap::location::operator==(const gamemap::location& a) const
{
return x == a.x && y == a.y;
@ -126,7 +136,7 @@ gamemap::gamemap(config& cfg, const std::string& data) : tiles_(1)
if(letterToTerrain_.count(c) == 0) {
if(isdigit(*i)) {
startingPositions_[c - '0'] = location(x,y);
c = CASTLE;
c = KEEP;
} else {
std::cerr << "Illegal character in map: (" << int(c) << ") '" << c << "'\n";
throw incorrect_format_exception("Illegal character");
@ -190,6 +200,47 @@ const std::vector<gamemap::TERRAIN>& gamemap::operator[](int index) const
return tiles_[index];
}
gamemap::TERRAIN gamemap::get_terrain(const gamemap::location& loc) const
{
if(on_board(loc))
return tiles_[loc.x][loc.y];
const std::map<location,TERRAIN>::const_iterator itor = borderCache_.find(loc);
if(itor != borderCache_.end())
return itor->second;
//if not on the board, decide based on what surrounding terrain is
TERRAIN items[6];
int nitems = 0;
location adj[6];
get_adjacent_tiles(loc,adj);
for(int n = 0; n != 6; ++n) {
if(on_board(adj[n])) {
items[nitems] = tiles_[adj[n].x][adj[n].y];
++nitems;
}
}
//count all the terrain types found, and see which one
//is the most common, and use it.
TERRAIN used_terrain = 0;
int terrain_count = 0;
for(int i = 0; i != nitems; ++i) {
if(items[i] != used_terrain) {
const int c = std::count(items+i+1,items+nitems,items[i]) + 1;
if(c > terrain_count) {
used_terrain = items[i];
terrain_count = c;
}
}
}
borderCache_.insert(std::pair<location,TERRAIN>(loc,used_terrain));
return used_terrain;
}
const gamemap::location& gamemap::starting_position(int n) const
{
return startingPositions_[n];

View file

@ -33,7 +33,7 @@ public:
//in dynamically because they're special. It's asserted that there will
//be corresponding entries for these types of terrain in the terrain
//configuration file.
enum { VOID_TERRAIN = ' ', CASTLE = 'C', TOWER = 't', FOREST = 'f' };
enum { VOID_TERRAIN = ' ', KEEP = 'K', CASTLE = 'C', TOWER = 't', FOREST = 'f' };
//the name of the terrain is the terrain itself, the underlying terrain
//is the name of the terrain for game-logic purposes. I.e. if the terrain
@ -59,6 +59,8 @@ public:
location(int x, int y) : x(x), y(y) {}
location(const config& cfg);
void write(config& cfg) const;
bool valid() const { return x >= 0 && y >= 0; }
int x, y;
@ -76,8 +78,7 @@ public:
//data should be a series of lines, with each character representing
//one hex on the map. Starting locations are represented by numbers,
//and will be of type keep.
gamemap(config& terrain_cfg,
const std::string& data); //throw(incorrect_format_exception)
gamemap(config& terrain_cfg, const std::string& data); //throw(incorrect_format_exception)
std::string write() const;
@ -88,6 +89,11 @@ public:
//allows lookup of terrain at a particular location.
const std::vector<TERRAIN>& operator[](int index) const;
//looks up terrain at a particular location. Hexes off the map
//may be looked up, and their 'emulated' terrain will also be returned.
//this allows proper drawing of the edges of the map
TERRAIN get_terrain(const location& loc) const;
//functions to manipulate starting positions of the different sides.
const location& starting_position(int side) const;
int num_starting_positions() const;
@ -129,6 +135,8 @@ private:
std::vector<std::vector<TERRAIN> > tiles_;
std::vector<location> towers_;
location startingPositions_[10];
mutable std::map<location,TERRAIN> borderCache_;
};
#endif

743
src/mapgen.cpp Normal file
View file

@ -0,0 +1,743 @@
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdlib>
#include <iostream>
#include <set>
#include <sstream>
#include <string>
#include <ctime>
#include <vector>
#include "mapgen.hpp"
#include "pathfind.hpp"
#include "util.hpp"
//function to generate a random map, from a string which describes
//the generator to use and its arguments
std::string random_generate_map(const std::string& parms)
{
//the first token is the name of the generator, tokens after
//that are arguments to the generator
std::vector<std::string> parameters = config::split(parms,' ');
map_generator* const generator = get_map_generator(parameters.front());
if(generator == NULL) {
std::cerr << "could not find map generator '" << parameters.front() << "'\n";
return "";
}
parameters.erase(parameters.begin());
return generator->create_map(parameters);
}
namespace {
typedef std::vector<std::vector<int> > height_map;
typedef std::vector<std::vector<char> > terrain_map;
//see http://216.239.39.104/search?q=cache:H2MSHn0AwBIJ:www.cosc.brocku.ca/Offerings/4V98/seminars/Terrain.ppt+height+map+algorithms&hl=en&ie=UTF-8 under
//'Hill Algorithm' for a description of this algorithm
//basically we generate alot of hills, each hill being centered at a certain point, with a certain radius - being a half sphere.
//Hills are combined additively to form a bumpy surface
//The size of each hill varies randomly from 1-hill_size.
//we generate 'iterations' hills in total.
//the range of heights is normalized to 0-1000
height_map generate_height_map(size_t width, size_t height,
size_t iterations, size_t hill_size)
{
height_map res(width,std::vector<int>(height,0));
for(size_t i = 0; i != iterations; ++i) {
//(x1,y1) is the location of the hill, and 'radius' is the radius of the hill.
//we iterate over all points, (x2,y2). The formula for the amount the height
//is increased by is radius - sqrt((x2-x1)^2 + (y2-y1)^2) with negative values
//ignored.
//
//rather than iterate over every single point, we can reduce the points to
//a rectangle that contains all the positive values for this formula --
//the rectangle is given by min_x,max_x,min_y,max_y
const int x1 = int(rand()%width);
const int y1 = int(rand()%height);
const int radius = rand()%hill_size + 1;
const int min_x = x1 - radius > 0 ? x1 - radius : 0;
const int max_x = x1 + radius < res.size() ? x1 + radius : res.size();
const int min_y = y1 - radius > 0 ? y1 - radius : 0;
const int max_y = y1 + radius < res.front().size() ? y1 + radius : res.front().size();
for(int x2 = min_x; size_t(x2) != max_x; ++x2) {
for(int y2 = min_y; size_t(y2) != max_y; ++y2) {
const int xdiff = (x2-x1);
const int ydiff = (y2-y1);
const int height = radius - int(sqrt(double(xdiff*xdiff + ydiff*ydiff)));
if(height > 0) {
res[x2][y2] += height;
}
}
}
}
//find the heighest and lowest points on the map for normalization
int heighest = 0, lowest = 100000, x;
for(x = 0; size_t(x) != res.size(); ++x) {
for(int y = 0; size_t(y) != res[x].size(); ++y) {
if(res[x][y] > heighest)
heighest = res[x][y];
if(res[x][y] < lowest)
lowest = res[x][y];
}
}
//normalize the heights to the range 0-1000
heighest -= lowest;
for(x = 0; size_t(x) != res.size(); ++x) {
for(int y = 0; size_t(y) != res[x].size(); ++y) {
res[x][y] -= lowest;
res[x][y] *= 1000;
if(heighest != 0)
res[x][y] /= heighest;
}
}
return res;
}
//function to generate a lake. It will create water at (x,y), and then have
//'lake_fall_off' % chance to make another water tile in each of the directions n,s,e,w.
//In each of the directions it does make another water tile, it will have 'lake_fall_off'/2 %
//chance to make another water tile in each of the directions. This will continue recursively.
void generate_lake(terrain_map& terrain, int x, int y, int lake_fall_off)
{
if(x < 0 || y < 0 || size_t(x) >= terrain.size() || size_t(y) >= terrain.front().size()) {
return;
}
terrain[x][y] = 'c';
if((rand()%100) < lake_fall_off) {
generate_lake(terrain,x+1,y,lake_fall_off/2);
}
if((rand()%100) < lake_fall_off) {
generate_lake(terrain,x-1,y,lake_fall_off/2);
}
if((rand()%100) < lake_fall_off) {
generate_lake(terrain,x,y+1,lake_fall_off/2);
}
if((rand()%100) < lake_fall_off) {
generate_lake(terrain,x,y-1,lake_fall_off/2);
}
}
typedef gamemap::location location;
//river generation:
//rivers have a source, and then keep on flowing until they meet another body of water,
//which they flow into, or until they reach the edge of the map. Rivers will always flow
//downhill, except that they can flow a maximum of 'river_uphill' uphill - this is to
//represent the water eroding the higher ground lower.
//
//Every possible path for a river will be attempted, in random order, and the first river
//path that can be found that makes the river flow into another body of water or off the map
//will be used. If no path can be found, then the river's generation will be aborted, and
//false will be returned. true is returned if the river is generated successfully.
bool generate_river_internal(const height_map& heights, terrain_map& terrain, int x, int y, std::vector<location>& river, std::set<location>& seen_locations, int river_uphill)
{
const bool on_map = x >= 0 && y >= 0 && x < heights.size() && y < heights.back().size();
if(on_map && !river.empty() && heights[x][y] > heights[river.back().x][river.back().y] + river_uphill) {
return false;
}
//if we're at the end of the river
if(!on_map || terrain[x][y] == 'c' || terrain[x][y] == 's') {
std::cerr << "generating river...\n";
//generate the river
for(std::vector<location>::const_iterator i = river.begin();
i != river.end(); ++i) {
terrain[i->x][i->y] = 'c';
}
return true;
}
location current_loc(x,y);
location adj[6];
get_adjacent_tiles(current_loc,adj);
static int items[6] = {0,1,2,3,4,5};
std::random_shuffle(items,items+4);
//mark that we have attempted from this location
seen_locations.insert(current_loc);
river.push_back(current_loc);
for(int a = 0; a != 6; ++a) {
const location& loc = adj[items[a]];
if(seen_locations.count(loc) == 0) {
const bool res = generate_river_internal(heights,terrain,loc.x,loc.y,river,seen_locations,river_uphill);
if(res) {
return true;
}
}
}
river.pop_back();
return false;
}
void generate_river(const height_map& heights, terrain_map& terrain, int x, int y, int river_uphill)
{
std::vector<location> river;
std::set<location> seen_locations;
generate_river_internal(heights,terrain,x,y,river,seen_locations,river_uphill);
}
//function to return a random tile at one of the borders of a map that is
//of the given dimensions.
location point_at_side(size_t width, size_t height)
{
const int side = rand()%4;
if(side < 2) {
const int x = rand()%width;
const int y = side == 0 ? 0 : height-1;
return location(x,y);
} else {
const int y = rand()%height;
const int x = side == 2 ? 0 : width-1;
return location(x,y);
}
}
//function which, given the map will output it in a valid format.
std::string output_map(const terrain_map& terrain)
{
std::stringstream res;
//remember that we only want the middle 1/9th of the map. All other
//segments of the map are there only to give the important middle part
//some context.
const size_t begin_x = terrain.size()/3;
const size_t end_x = begin_x*2;
const size_t begin_y = terrain.front().size()/3;
const size_t end_y = begin_y*2;
for(size_t y = begin_y; y != end_y; ++y) {
for(size_t x = begin_x; x != end_x; ++x) {
res << terrain[x][y];
}
res << "\n";
}
return res.str();
}
//an object that will calculate the cost of building a road over terrain
//for use in the a_star_search algorithm.
struct road_path_calculator
{
road_path_calculator(const terrain_map& terrain, const config& cfg)
: map_(terrain), cfg_(cfg),
//find out how windy roads should be.
windiness_(maximum<int>(1,atoi(cfg["road_windiness"].c_str()))) {}
double cost(const location& loc, double so_far) const;
private:
const terrain_map& map_;
const config& cfg_;
int windiness_;
mutable std::map<char,double> cache_;
};
double road_path_calculator::cost(const location& loc, double so_far) const
{
if(loc.x < 0 || loc.y < 0 || loc.x >= map_.size() || loc.y >= map_.front().size())
return 100000.0;
//we multiply the cost by a random amount depending upon how 'windy' the road should
//be. If windiness is 1, that will mean that the cost is always genuine, and so
//the road always takes the shortest path. If windiness is greater than 1, we sometimes
//over-report costs for some segments, to make the road wind a little.
const double windiness = (double(rand()%windiness_) + 1.0);
const char c = map_[loc.x][loc.y];
const std::map<char,double>::const_iterator itor = cache_.find(c);
if(itor != cache_.end())
return itor->second*windiness;
static std::string terrain(1,'x');
terrain[0] = c;
const config* const child = cfg_.find_child("road_cost","terrain",terrain);
double res = 100000.0;
if(child != NULL) {
res = double(atoi((*child)["cost"].c_str()));
}
cache_.insert(std::pair<char,double>(c,res));
return windiness*res;
}
//function to generate the map.
std::string generate_map(size_t width, size_t height,
size_t iterations, size_t hill_size,
size_t max_lakes, size_t nvillages, size_t nplayers,
const config& cfg)
{
//find out what the 'flatland' on this map is. i.e. grassland.
std::string flatland = cfg["default_flatland"];
if(flatland == "") {
flatland = "g";
}
const char grassland = flatland[0];
//we want to generate a map that is 9 times bigger than the
//actual size desired. Only the middle part of the map will be
//used, but the rest is so that the map we end up using can
//have a context (e.g. rivers flowing from out of the map into
//the map, same for roads, etc etc)
width *= 3;
height *= 3;
//generate the height of everything.
const height_map heights = generate_height_map(width,height,iterations,hill_size);
//the configuration file should contain a number of [height] tags:
//[height]
//height=n
//terrain=x
//[/height]
//these should be in descending order of n. They are checked sequentially, and if
//height is greater than n for that tile, then the tile is set to terrain type x.
terrain_map terrain(width,std::vector<char>(height,grassland));
size_t x, y;
for(x = 0; x != heights.size(); ++x) {
for(y = 0; y != heights[x].size(); ++y) {
const int val = heights[x][y];
const config::child_list& items = cfg.get_children("height");
for(config::child_list::const_iterator i = items.begin(); i != items.end(); ++i) {
const int height = atoi((**i)["height"].c_str());
if(val >= height) {
const std::string& c = (**i)["terrain"];
terrain[x][y] = c.empty() ? 'g' : c[0];
break;
}
}
}
}
//now that we have our basic set of flatland/hills/mountains/water, we can place lakes
//and rivers on the map. All rivers are sourced at a lake. Lakes must be in high land -
//at least 'min_lake_height'. (Note that terrain below a certain altitude may be made
//into bodies of water in the code above - i.e. 'sea', but these are not considered 'lakes' because
//they are not sources of rivers).
//
//we attempt to place 'max_lakes' lakes. Each lake will be placed at a random location,
//if that random location meets the minimum terrain requirements for a lake.
//We will also attempt to source a river from each lake.
const int nlakes = max_lakes > 0 ? (rand()%max_lakes) : 0;
for(size_t lake = 0; lake != nlakes; ++lake) {
for(int tries = 0; tries != 100; ++tries) {
const int x = rand()%width;
const int y = rand()%height;
if(heights[x][y] > atoi(cfg["min_lake_height"].c_str())) {
generate_river(heights,terrain,x,y,atoi(cfg["river_frequency"].c_str()));
generate_lake(terrain,x,y,atoi(cfg["lake_size"].c_str()));
break;
}
}
}
//convert grassland terrain to other types of flat terrain.
//we generate a 'temperature map' which uses the height generation algorithm to
//generate the temperature levels all over the map. Then we can use a combination
//of height and terrain to divide flatland up into more interesting types than the default
const height_map temperature_map = generate_height_map(width,height,
atoi(cfg["temperature_iterations"].c_str()),
atoi(cfg["temperature_size"].c_str()));
//iterate over every flatland tile, and determine what type of flatland it is,
//based on our [flatland] tags.
for(x = 0; x != width; ++x) {
for(y = 0; y != width; ++y) {
if(terrain[x][y] != grassland)
continue;
const int temperature = temperature_map[x][y];
const int height = heights[x][y];
//iterate over our list of [flatland] tags. Each tag specifies ranges
//for temperature and height, and if that range is met, then the terrain
//becomes the type specified. For instance, a tag to put snow in
//high areas with low temperature would look like:
//[flatland]
//max_temp=200
//min_height=600
//[/flatland]
const config::child_list& items = cfg.get_children("flatland");
for(config::child_list::const_iterator i = items.begin(); i != items.end(); ++i) {
const std::string& min_temp = (**i)["min_temperature"];
const std::string& max_temp = (**i)["max_temperature"];
const std::string& min_height = (**i)["min_height"];
const std::string& max_height = (**i)["max_height"];
if(min_temp.empty() == false && atoi(min_temp.c_str()) > temperature)
continue;
if(max_temp.empty() == false && atoi(max_temp.c_str()) < temperature)
continue;
if(min_height.empty() == false && atoi(min_height.c_str()) > height)
continue;
if(max_height.empty() == false && atoi(max_height.c_str()) < height)
continue;
//we are in the right range, so set the terrain and go
//on to the next tile.
const std::string& set_to = (**i)["terrain"];
if(set_to.empty() == false)
terrain[x][y] = set_to[0];
break;
}
}
}
//place roads. We select two tiles at random locations on the borders of the map,
//and try to build roads between them.
const size_t nroads = atoi(cfg["roads"].c_str());
for(size_t road = 0; road != nroads; ++road) {
//we want the locations to be on the portion of the map we're actually going
//to use, since roads on other parts of the map won't have any influence,
//and doing it like this will be quicker.
location src = point_at_side(width/3 + 2,height/3 + 2);
location dst = point_at_side(width/3 + 2,height/3 + 2);
src.x += width/3 - 1;
src.y += height/3 - 1;
dst.x += width/3 - 1;
dst.y += height/3 - 1;
//if the road isn't very interesting (on the same border), don't draw it
if(src.x == dst.x || src.y == dst.y) {
continue;
}
const road_path_calculator calc(terrain,cfg);
if(calc.cost(src,0.0) >= 1000.0 || calc.cost(dst,0.0) >= 1000.0) {
continue;
}
//search a path out for the road
const paths::route rt = a_star_search(src,dst,1000.0,calc);
//draw the road. If the search failed, rt.steps will simply be empty
for(std::vector<location>::const_iterator step = rt.steps.begin(); step != rt.steps.end(); ++step) {
const int x = step->x;
const int y = step->y;
if(x < 0 || y < 0 || x >= width || y >= height)
continue;
//find the configuration which tells us what to convert this tile to
//to make it into a road.
const std::string str(1,terrain[x][y]);
const config* const child = cfg.find_child("road_cost","terrain",str);
if(child != NULL) {
//convert to bridge means that we want to convert depending
//upon the direction the road is going.
//typically it will be in a format like,
//convert_to_bridge=|,/,\
// '|' will be used if the road is going north-south
// '/' will be used if the road is going south west-north east
// '\' will be used if the road is going south east-north west
//the terrain will be left unchanged otherwise (if there is no clear
//direction)
const std::string& convert_to_bridge = (*child)["convert_to_bridge"];
if(convert_to_bridge.empty() == false) {
if(step == rt.steps.begin() || step+1 == rt.steps.end())
continue;
const location& last = *(step-1);
const location& next = *(step+1);
location adj[6];
get_adjacent_tiles(*step,adj);
size_t direction = 0;
//if we are going north-south
if(last == adj[0] && next == adj[3] || last == adj[3] && next == adj[0]) {
direction = 0;
}
//if we are going south west-north east
else if(last == adj[1] && next == adj[4] || last == adj[4] && next == adj[1]) {
direction = 1;
}
//if we are going south east-north west
else if(last == adj[2] && next == adj[5] || last == adj[5] && next == adj[2]) {
direction = 2;
} else {
continue;
}
const std::vector<std::string> items = config::split(convert_to_bridge);
if(direction < items.size() && items[direction].empty() == false) {
terrain[x][y] = items[direction][0];
}
continue;
}
//just a plain terrain substitution for a road
const std::string& convert_to = (*child)["convert_to"];
if(convert_to.empty() == false)
terrain[x][y] = convert_to[0];
}
}
}
//place villages. We attempt to place nvillages, all at random locations.
//After a location is chosen, we can through [village] tags to see
//what kind of village we should place on that type of terrain. If no
//[village] tag is found for the terrain type (e.g. deep water) no village
//will be placed.
std::set<location> villages;
for(size_t village = 0; village != nvillages; ++village) {
const int x = rand()%height;
const int y = rand()%width;
const std::string str(1,terrain[x][y]);
const config* const child = cfg.find_child("village","terrain",str);
if(child != NULL) {
const std::string& convert_to = (*child)["convert_to"];
if(convert_to.empty() == false)
terrain[x][y] = convert_to[0];
}
}
//try to find configuration for castles.
const config* const castle_config = cfg.child("castle");
if(castle_config == NULL) {
std::cerr << "Could not find castle configuration\n";
return "";
}
//castle configuration tag contains a 'valid_terrain' attribute which is a list of
//terrains that the castle may appear on.
const std::vector<std::string> castle_terrains = config::split((*castle_config)["valid_terrain"]);
//attempt to place castles at random. Once we have placed castles, we run a sanity
//check to make sure that the castles are well-placed. If the castles are not well-placed,
//we try again. Definition of 'well-placed' is if no two castles are closer than
//'min_distance' hexes from each other, and the castles appear on a terrain listed
//in 'valid_terrain'.
int ntries = 0;
bool placing_bad = true;
while(placing_bad) {
if(++ntries > 5000) {
std::cerr << "could not sanely place castles. Aborting.\n";
return "";
}
std::vector<location> castles;
for(size_t player = 0; player != nplayers; ++player) {
const int x = (rand()%(height/3)) + height/3;
const int y = (rand()%(width/3)) + width/3;
castles.push_back(location(x,y));
}
//make sure all castles are placed on valid terrain. Check the castle tile
//itself, and all surrounding tiles
placing_bad = false;
std::vector<location>::const_iterator c;
for(c = castles.begin(); c != castles.end(); ++c) {
const int x = c->x;
const int y = c->y;
const char terrains[] = {terrain[x][y],terrain[x+1][y],terrain[x-1][y],
terrain[x][y+1],terrain[x+1][y+1],terrain[x-1][y+1],
terrain[x][y-1],terrain[x+1][y-1],terrain[x-1][y-1]};
for(int n = 0; n != sizeof(terrains)/sizeof(*terrains); ++n) {
const std::string t(1,terrains[n]);
if(std::find(castle_terrains.begin(),castle_terrains.end(),t) == castle_terrains.end()) {
placing_bad = true;
break;
}
}
if(placing_bad) {
break;
}
}
if(placing_bad)
continue;
//make sure all castles are a minimum distance away from each other
const int min_distance = atoi((*castle_config)["min_distance"].c_str());
for(std::vector<location>::const_iterator c1 = castles.begin(); c1 != castles.end(); ++c1) {
for(std::vector<location>::const_iterator c2 = c1+1; c2 != castles.end(); ++c2) {
if(distance_between(*c1,*c2) < min_distance) {
placing_bad = true;
break;
}
}
}
if(placing_bad)
continue;
//plonk down the castles.
for(c = castles.begin(); c != castles.end(); ++c) {
const int x = c->x;
const int y = c->y;
const int player = c - castles.begin();
terrain[x][y] = '1' + player;
terrain[x-1][y] = 'C';
terrain[x+1][y] = 'C';
terrain[x][y-1] = 'C';
terrain[x][y+1] = 'C';
terrain[x-1][y-1] = 'C';
terrain[x-1][y+1] = 'C';
terrain[x+1][y-1] = 'C';
terrain[x+1][y+1] = 'C';
}
}
return output_map(terrain);
}
typedef std::map<std::string,map_generator*> generator_map;
generator_map generators;
}
map_generator::manager::manager(const config& game_config)
{
map_generator* const gen = new default_map_generator(game_config);
assert(generators.count(gen->name()) == 0);
generators[gen->name()] = gen;
}
map_generator::manager::~manager()
{
for(generator_map::iterator i = generators.begin(); i != generators.end(); ++i) {
delete i->second;
}
generators.clear();
}
map_generator* get_map_generator(const std::string& name)
{
const generator_map::iterator i = generators.find(name);
if(i != generators.end())
return i->second;
else
return NULL;
}
default_map_generator::default_map_generator(const config& game_config)
: width_(40), height_(40), iterations_(1000), hill_size_(10), max_lakes_(20),
nvillages_(300), nplayers_(2), cfg_(NULL)
{
const config* const cfg = game_config.find_child("map_generator","name",name());
if(cfg != NULL) {
cfg_ = cfg;
const int width = ::atoi((*cfg)["width"].c_str());
if(width > 0)
width_ = width;
const int height = ::atoi((*cfg)["height"].c_str());
if(height > 0)
height_ = height;
const int iterations = ::atoi((*cfg)["iterations"].c_str());
if(iterations > 0)
iterations_ = iterations;
const int hill_size = ::atoi((*cfg)["hill_size"].c_str());
if(hill_size > 0)
hill_size_ = hill_size;
const int max_lakes = ::atoi((*cfg)["max_lakes"].c_str());
if(max_lakes > 0)
max_lakes_ = max_lakes;
const int nvillages = ::atoi((*cfg)["villages"].c_str());
if(nvillages > 0)
nvillages_ = nvillages;
const int nplayers = ::atoi((*cfg)["players"].c_str());
if(nplayers > 0)
nplayers_ = nplayers;
}
}
bool default_map_generator::allow_user_config() const { return false; }
void default_map_generator::user_config(display& disp) {}
std::string default_map_generator::name() const { return "default"; }
std::string default_map_generator::create_map(const std::vector<std::string>& args) const
{
if(cfg_ != NULL)
return generate_map(width_,height_,iterations_,hill_size_,max_lakes_,nvillages_,nplayers_,*cfg_);
else
return "";
}
#ifdef TEST_MAPGEN
int main(int argc, char** argv)
{
int x = 50, y = 50, iterations = 50, hill_size = 50, lakes=3,
nvillages = 500, nplayers = 2;
if(argc >= 2) {
x = atoi(argv[1]);
}
if(argc >= 3) {
y = atoi(argv[2]);
}
if(argc >= 4) {
iterations = atoi(argv[3]);
}
if(argc >= 5) {
hill_size = atoi(argv[4]);
}
if(argc >= 6) {
lakes = atoi(argv[5]);
}
if(argc >= 7) {
nvillages = atoi(argv[6]);
}
if(argc >= 8) {
nplayers = atoi(argv[7]);
}
srand(time(NULL));
std::cout << generate_map(x,y,iterations,hill_size,lakes,nvillages,nplayers) << "\n";
}
#endif

58
src/mapgen.hpp Normal file
View file

@ -0,0 +1,58 @@
#ifndef MAP_GEN_HPP_INCLUDED
#define MAP_GEN_HPP_INCLUDED
#include "config.hpp"
#include "display.hpp"
#include <string>
std::string random_generate_map(const std::string& parms);
class map_generator
{
public:
//returns true iff the map generator has an interactive screen
//which allows the user to modify how the generator behaves
virtual bool allow_user_config() const = 0;
//display the interactive screen which allows the user to
//modify how the generator behaves. (This function will not
//be called if allow_user_config() returns false)
virtual void user_config(display& disp) = 0;
//returns a string identifying the generator by name. The name should
//not contain spaces.
virtual std::string name() const = 0;
//creates a new map and returns it. args may contain arguments to
//the map generator
virtual std::string create_map(const std::vector<std::string>& args) const = 0;
struct manager
{
manager(const config& game_config);
~manager();
};
};
map_generator* get_map_generator(const std::string& name);
class default_map_generator : public map_generator
{
public:
default_map_generator(const config& game_config);
bool allow_user_config() const;
void user_config(display& disp);
std::string name() const;
std::string create_map(const std::vector<std::string>& args) const;
private:
size_t width_, height_, iterations_, hill_size_, max_lakes_, nvillages_, nplayers_;
const config* cfg_;
};
#endif

View file

@ -16,6 +16,7 @@
#include "language.hpp"
#include "log.hpp"
#include "image.hpp"
#include "mapgen.hpp"
#include "multiplayer.hpp"
#include "multiplayer_client.hpp"
#include "network.hpp"
@ -286,7 +287,7 @@ int play_multiplayer(display& disp, game_data& units_data, config cfg,
font::draw_text(&disp,disp.screen_area(),12,font::GOOD_COLOUR,
string_table["name_of_game"] + ":",(disp.x()-width)/2+10,(disp.y()-height)/2+38);
gui::textbox name_entry(disp,width-20,string_table["game_prefix"] + preferences::login() + string_table["game_postfix"]);
name_entry.set_location((disp.x()-width)/2+10,(disp.y()-height)/2+55);
name_entry.set_position((disp.x()-width)/2+10,(disp.y()-height)/2+55);
//Maps
font::draw_text(&disp,disp.screen_area(),12,font::GOOD_COLOUR,
@ -317,9 +318,9 @@ int play_multiplayer(display& disp, game_data& units_data, config cfg,
rect.h = 12;
SDL_Surface* village_bg=get_surface_portion(disp.video().getSurface(), rect);
font::draw_text(&disp,disp.screen_area(),12,font::GOOD_COLOUR,
"Turns: 50",rect.x,rect.y);
string_table["turns"] + ": 50",rect.x,rect.y);
rect.y = (disp.y()-height)/2+100;
rect.h = name_entry.width();
rect.h = name_entry.location().w;
gui::slider turns_slider(disp,rect,0.38);
@ -329,9 +330,9 @@ int play_multiplayer(display& disp, game_data& units_data, config cfg,
rect.w = ((disp.x()-width)/2+width)-((disp.x()-width)/2+(int)(width*0.4)+maps_menu.width()+19)-10;
rect.h = 12;
font::draw_text(&disp,disp.screen_area(),12,font::GOOD_COLOUR,
"Village Gold: 1",rect.x,rect.y);
string_table["village_gold"] + ": 1",rect.x,rect.y);
rect.y = (disp.y()-height)/2+147;
rect.h = name_entry.width();
rect.h = name_entry.location().w;
gui::slider villagegold_slider(disp,rect,0.0);
//FOG of war
@ -403,15 +404,12 @@ int play_multiplayer(display& disp, game_data& units_data, config cfg,
load_game(units_data,game,state);
if(state.campaign_type != "multiplayer") {
gui::show_dialog(disp,NULL,"",
"This is not a multiplayer save",gui::OK_ONLY);
gui::show_dialog(disp,NULL,"",string_table["not_multiplayer_save_message"],gui::OK_ONLY);
break;
}
if(state.version != game_config::version) {
const int res = gui::show_dialog(disp,NULL,"",
string_table["version_save_message"],
gui::YES_NO);
const int res = gui::show_dialog(disp,NULL,"",string_table["version_save_message"],gui::YES_NO);
if(res == 1)
break;
}
@ -430,6 +428,10 @@ int play_multiplayer(display& disp, game_data& units_data, config cfg,
recorder = replay(state.replay_data);
//if this is a snapshot save, we don't want to use the replay data
if(loaded_level["snapshot"] == "yes")
recorder.set_to_end();
//add the replay data under the level data so clients can
//receive it
level_ptr->clear_children("replay");
@ -791,7 +793,9 @@ int play_multiplayer(display& disp, game_data& units_data, config cfg,
fog_game.process(mousex,mousey,left_button);
shroud_game.process(mousex,mousey,left_button);
observers_game.process(mousex,mousey,left_button);
name_entry.process();
events::raise_process_event();
events::raise_draw_event();
//Game turns are 20 to 99
//FIXME: Should never be a - number, but it is sometimes
@ -839,6 +843,16 @@ int play_multiplayer(display& disp, game_data& units_data, config cfg,
map_data = read_file("data/maps/" + (*level_ptr)["map"]);
}
//if the map should be randomly generated
if(map_data == "" && (*level_ptr)["map_generation"] != "") {
map_data = random_generate_map((*level_ptr)["map_generation"]);
//record the map data of the map, so that when we send to
//remote clients, they will use the given map, and won't try
//to generate their own.
(*level_ptr)["map_data"] = map_data;
}
gamemap map(cfg,map_data);
const scoped_sdl_surface mini(image::getMinimap(175,175,map));

View file

@ -97,7 +97,7 @@ RESULT enter(display& disp, config& game_data)
join_game.set_xy(19,545);
new_game.set_xy(19+join_game.width()+5,545);
quit_game.set_xy(19+join_game.width()+5+new_game.width()+5,545);
message_entry.set_location(19,725);
message_entry.set_position(19,725);
message_entry.set_width(832);
update_whole_screen();
@ -153,7 +153,8 @@ RESULT enter(display& disp, config& game_data)
return QUIT;
}
message_entry.process();
events::raise_process_event();
events::raise_draw_event();
config data;

View file

@ -174,19 +174,20 @@ connection receive_data(config& cfg, connection connection_num, int timeout)
const int starting_ticks = SDL_GetTicks();
std::cerr << "checking sockets...\n";
const int res = SDLNet_CheckSockets(socket_set,timeout);
if(res <= 0) {
return 0;
}
for(sockets_list::const_iterator i = sockets.begin();
i != sockets.end(); ++i) {
for(sockets_list::const_iterator i = sockets.begin(); i != sockets.end(); ++i) {
if(SDLNet_SocketReady(*i)) {
std::string buffer;
for(;;) {
char c;
const int len = SDLNet_TCP_Recv(*i,&c,1);
if(len == 0) {
break;
} else if(len < 0) {
@ -248,8 +249,6 @@ void send_data(const config& cfg, connection connection_num)
return;
}
std::cerr << "a\n";
assert(connection_num != server_socket);
std::string value = cfg.write();
@ -264,4 +263,15 @@ void send_data(const config& cfg, connection connection_num)
}
}
void send_data_all_except(const config& cfg, connection connection_num)
{
for(sockets_list::const_iterator i = sockets.begin(); i != sockets.end(); ++i) {
if(*i == connection_num)
continue;
assert(*i && *i != server_socket);
send_data(cfg,*i);
}
}
} //end namespace network

View file

@ -74,6 +74,9 @@ connection receive_data(config& cfg, connection connection_num=0,
//to all peers if connection_num is 0. throws error.
void send_data(const config& cfg, connection connection_num=0);
//function to send data to all peers except 'connection_num'
void send_data_all_except(const config& cfg, connection connection_num);
struct error
{
error(const std::string& msg, connection sock=0)

View file

@ -78,19 +78,19 @@ void get_adjacent_tiles(const gamemap::location& a, gamemap::location* res)
res->y = a.y-1;
++res;
res->x = a.x+1;
res->y = a.y - is_even(a.x);
res->y = a.y - (is_even(a.x) ? 1:0);
++res;
res->x = a.x+1;
res->y = a.y + is_odd(a.x);
res->y = a.y + (is_odd(a.x) ? 1:0);
++res;
res->x = a.x;
res->y = a.y+1;
++res;
res->x = a.x-1;
res->y = a.y + is_odd(a.x);
res->y = a.y + (is_odd(a.x) ? 1:0);
++res;
res->x = a.x-1;
res->y = a.y - is_even(a.x);
res->y = a.y - (is_even(a.x) ? 1:0);
}
bool tiles_adjacent(const gamemap::location& a, const gamemap::location& b)
@ -102,7 +102,7 @@ bool tiles_adjacent(const gamemap::location& a, const gamemap::location& b)
const int xdiff = abs(a.x - b.x);
const int ydiff = abs(a.y - b.y);
return ydiff == 1 && a.x == b.x || xdiff == 1 && a.y == b.y ||
xdiff == 1 && ydiff == 1 && (a.y > b.y ? (a.x%2) == 1 : (b.x%2) == 1);
xdiff == 1 && ydiff == 1 && (a.y > b.y ? is_odd(a.x) : is_odd(b.x));
}
size_t distance_between(const gamemap::location& a, const gamemap::location& b)

View file

@ -154,8 +154,10 @@ paths::route a_star_search(const gamemap::location& src,
using namespace detail;
typedef gamemap::location location;
std::list<node> open_list, closed_list;
std::map<location,double> lowest_f;
open_list.push_back(node(src,dst,0.0,NULL,teleports));
lowest_f.insert(std::pair<location,double>(src,0.0));
while(!open_list.empty()) {
@ -206,24 +208,15 @@ paths::route a_star_search(const gamemap::location& src,
const node nd(locs[j],dst,lowest->g+obj.cost(locs[j],lowest->g),
&*lowest,teleports);
for(i = open_list.begin(); i != open_list.end(); ++i) {
if(i->loc == nd.loc && i->f <= nd.f) {
break;
const std::map<location,double>::iterator current = lowest_f.find(nd.loc);
if(current != lowest_f.end()) {
if(current->second <= nd.f) {
continue;
} else {
current->second = nd.f;
}
}
if(i != open_list.end()) {
continue;
}
for(i = closed_list.begin(); i != closed_list.end(); ++i) {
if(i != lowest && i->loc == nd.loc && i->f <= nd.f) {
break;
}
}
if(i != closed_list.end()) {
continue;
} else {
lowest_f.insert(std::pair<location,double>(nd.loc,nd.f));
}
open_list.push_back(nd);

View file

@ -16,6 +16,7 @@
#include "hotkeys.hpp"
#include "intro.hpp"
#include "language.hpp"
#include "mapgen.hpp"
#include "network.hpp"
#include "playlevel.hpp"
#include "playturn.hpp"
@ -40,6 +41,11 @@ LEVEL_RESULT play_level(game_data& gameinfo, config& terrain_config,
map_data = read_file("data/maps/" + (*level)["map"]);
}
//if the map should be randomly generated
if(map_data == "" && (*level)["map_generation"] != "") {
map_data = random_generate_map((*level)["map_generation"]);
}
gamemap map(terrain_config,map_data);
CKey key;
@ -51,17 +57,6 @@ LEVEL_RESULT play_level(game_data& gameinfo, config& terrain_config,
const config::child_list& unit_cfg = level->get_children("side");
for(config::child_list::const_iterator ui = unit_cfg.begin(); ui != unit_cfg.end(); ++ui) {
unit new_unit(gameinfo, **ui);
if(ui == unit_cfg.begin()) {
for(std::vector<unit>::iterator it = state_of_game.available_units.begin();
it != state_of_game.available_units.end(); ++it) {
if(it->can_recruit()) {
new_unit = *it;
state_of_game.available_units.erase(it);
break;
}
}
}
std::string gold = (**ui)["gold"];
if(gold.empty())
@ -73,15 +68,33 @@ LEVEL_RESULT play_level(game_data& gameinfo, config& terrain_config,
ngold = state_of_game.gold;
}
const gamemap::location& start_pos = map.starting_position(new_unit.side());
//if this side tag describes the leader of the side
if((**ui)["no_leader"] != "yes") {
unit new_unit(gameinfo, **ui);
if(!start_pos.valid() && new_unit.side() == 1) {
throw gamestatus::load_game_failed("No starting position for side 1");
}
//search the recall list for leader units, and if there is
//one, use it in place of the config-described unit
if(ui == unit_cfg.begin()) {
for(std::vector<unit>::iterator it = state_of_game.available_units.begin();
it != state_of_game.available_units.end(); ++it) {
if(it->can_recruit()) {
new_unit = *it;
state_of_game.available_units.erase(it);
break;
}
}
}
if(start_pos.valid()) {
units.insert(std::pair<gamemap::location,unit>(
map.starting_position(new_unit.side()), new_unit));
const gamemap::location& start_pos = map.starting_position(new_unit.side());
if(!start_pos.valid() && new_unit.side() == 1) {
throw gamestatus::load_game_failed("No starting position for side 1");
}
if(start_pos.valid()) {
units.insert(std::pair<gamemap::location,unit>(
map.starting_position(new_unit.side()), new_unit));
}
}
teams.push_back(team(**ui,ngold));
@ -110,10 +123,11 @@ LEVEL_RESULT play_level(game_data& gameinfo, config& terrain_config,
const std::string& y = (**su)["y"];
const gamemap::location loc(**su);
if(x.size() == 0 || y.size() == 0 || !map.on_board(loc)) {
if(x.empty() || y.empty() || !map.on_board(loc)) {
state_of_game.available_units.push_back(new_unit);
} else {
units.insert(std::pair<gamemap::location,unit>(loc,new_unit));
std::cerr << "inserting unit for side " << new_unit.side() << "\n";
}
}
}
@ -150,18 +164,22 @@ LEVEL_RESULT play_level(game_data& gameinfo, config& terrain_config,
gui.add_overlay(gamemap::location(**overlay),(**overlay)["image"]);
}
for(unit_map::iterator i = units.begin(); i != units.end(); ++i) {
i->second.new_turn();
}
gui.scroll_to_tile(map.starting_position(1).x,map.starting_position(1).y,
display::WARP);
bool replaying = (recorder.empty() == false);
//if a team is specified whose turn it is, it means we're loading a game
//instead of starting a fresh one
const bool loading_game = (*level)["playing_team"].empty() == false;
int first_player = atoi((*level)["playing_team"].c_str());
if(first_player < 0 || first_player >= int(teams.size())) {
first_player = 0;
}
int turn = 1;
std::cout << "starting main loop\n";
for(bool first_time = true; true; first_time = false) {
for(bool first_time = true; true; first_time = false, first_player = 0) {
try {
if(first_time) {
@ -178,7 +196,7 @@ LEVEL_RESULT play_level(game_data& gameinfo, config& terrain_config,
std::cerr << "turn: " << turn++ << "\n";
for(std::vector<team>::iterator team_it = teams.begin();
for(std::vector<team>::iterator team_it = teams.begin()+first_player;
team_it != teams.end(); ++team_it) {
const int player_number = (team_it - teams.begin()) + 1;
@ -186,13 +204,19 @@ LEVEL_RESULT play_level(game_data& gameinfo, config& terrain_config,
if(team_units(units,player_number) == 0)
continue;
for(unit_map::iterator i = units.begin(); i != units.end(); ++i) {
if(i->second.side() == player_number) {
i->second.new_turn();
}
}
//we want to work out if units for this player should get healed, and the
//player should get income now. healing/income happen if it's not the first
//turn of processing, or if we are loading a game, and this is not the
//player it started with.
const bool turn_refresh = !first_time || loading_game && team_it != teams.begin()+first_player;
if(turn_refresh) {
for(unit_map::iterator i = units.begin(); i != units.end(); ++i) {
if(i->second.side() == player_number) {
i->second.new_turn();
}
}
if(!first_time) {
team_it->new_turn();
//if the expense is less than the number of villages owned,
@ -202,17 +226,16 @@ LEVEL_RESULT play_level(game_data& gameinfo, config& terrain_config,
if(expense > 0) {
team_it->spend_gold(expense);
}
calculate_healing(gui,map,units,player_number);
}
gui.set_playing_team(size_t(player_number-1));
clear_shroud(gui,map,gameinfo,units,teams,player_number-1);
calculate_healing(gui,map,units,player_number);
//scroll the map to the leader
const unit_map::iterator leader =
find_leader(units,player_number);
const unit_map::iterator leader = find_leader(units,player_number);
if(leader != units.end() && !recorder.skipping()) {
const hotkey::basic_handler key_events_handler(gui);
@ -295,10 +318,14 @@ LEVEL_RESULT play_level(game_data& gameinfo, config& terrain_config,
}
if(res && cfg.child("turn") != NULL) {
//forward the data to other peers
network::send_data_all_except(cfg,res);
break;
}
const int ncommand = recorder.ncommands();
turn_data.turn_slice();
turn_data.send_data(ncommand);
gui.draw();
}
@ -315,7 +342,8 @@ LEVEL_RESULT play_level(game_data& gameinfo, config& terrain_config,
gui::YES_NO,NULL,NULL,"",&output);
if(res == 0 && output.empty() == false) {
recorder.mark_current();
recorder.save_game(gameinfo,output);
config starting_pos;
recorder.save_game(gameinfo,output,starting_pos);
}
return QUIT;
@ -437,7 +465,8 @@ LEVEL_RESULT play_level(game_data& gameinfo, config& terrain_config,
gui::OK_CANCEL,NULL,NULL,
string_table["save_game_label"],&label);
if(res == 0) {
recorder.save_game(gameinfo,label);
config starting_pos;
recorder.save_game(gameinfo,label,starting_pos);
}
return QUIT;

View file

@ -616,6 +616,11 @@ void turn_info::show_menu()
menu.push_back(create_unit_debug);
}
const unit_map::iterator leader = find_leader(units_,gui_.viewing_team()+1);
if(network::nconnections() > 0 && leader != units_.end()) {
menu.push_back(string_table["speak"]);
}
if(un != units_.end()) {
menu.push_back(string_table["describe_unit"]);
@ -634,7 +639,26 @@ void turn_info::show_menu()
menu.pop_back();
}
if(result == create_unit_debug) {
if(result == string_table["speak"]) {
std::string message;
const int res = gui::show_dialog(gui_,NULL,"",string_table["speak"],gui::OK_CANCEL,NULL,NULL,
string_table["message"] + ":", &message);
if(res == 0) {
config cfg;
cfg["description"] = leader->second.description();
cfg["message"] = message;
char buf[50];
sprintf(buf,"%d",leader->second.side());
cfg["side"] = buf;
recorder.speak(cfg);
dialogs::unit_speak(cfg,gui_,units_);
//speaking is an unretractable operation
undo_stack_.clear();
redo_stack_.clear();
}
} else if(result == create_unit_debug) {
std::vector<std::string> options;
std::vector<unit> unit_choices;
for(game_data::unit_type_map::const_iterator i = gameinfo_.unit_types.begin();
@ -669,7 +693,8 @@ void turn_info::show_menu()
} else if(result == string_table["status_table"]) {
status_table();
} else if(result == string_table["unit_list"]) {
const std::string heading = string_table["name"] + "," +
const std::string heading = string_table["type"] + "," +
string_table["name"] + "," +
string_table["hp"] + "," +
string_table["xp"] + "," +
string_table["moves"] + "," +
@ -685,7 +710,9 @@ void turn_info::show_menu()
continue;
std::stringstream row;
row << i->second.name() << "," << i->second.hitpoints()
row << i->second.type().language_name() << ","
<< i->second.description() << ","
<< i->second.hitpoints()
<< "/" << i->second.max_hitpoints() << ","
<< i->second.experience() << "/";
@ -764,7 +791,9 @@ void turn_info::end_turn()
return;
end_turn_ = true;
recorder.save_game(gameinfo_,string_table["auto_save"]);
config start_pos;
write_game_snapshot(start_pos);
recorder.save_game(gameinfo_,string_table["auto_save"],start_pos);
recorder.end_turn();
}
@ -1028,11 +1057,57 @@ void turn_info::save_game()
const int res = dialogs::get_save_name(gui_,"",string_table["save_game_label"],&label,gui::OK_CANCEL);
if(res == 0) {
recorder.save_game(gameinfo_,label);
config start;
write_game_snapshot(start);
recorder.save_game(gameinfo_,label,start);
gui::show_dialog(gui_,NULL,"",string_table["save_confirm_message"], gui::OK_ONLY);
}
}
void turn_info::write_game_snapshot(config& start) const
{
start["snapshot"] = "yes";
char buf[50];
sprintf(buf,"%d",gui_.playing_team());
start["playing_team"] = buf;
for(std::vector<team>::const_iterator t = teams_.begin(); t != teams_.end(); ++t) {
const int side_num = t - teams_.begin() + 1;
config& side = start.add_child("side");
t->write(side);
side["no_leader"] = "yes";
sprintf(buf,"%d",side_num);
side["side"] = buf;
for(std::map<gamemap::location,unit>::const_iterator i = units_.begin();
i != units_.end(); ++i) {
if(i->second.side() == side_num) {
config& u = side.add_child("unit");
i->first.write(u);
i->second.write(u);
}
}
}
status_.write(start);
game_events::write_events(start);
write_game(state_of_game_,start);
start["gold"] = "-1000000"; //just make sure gold is read in from the teams
//copy over important scenario stats
start["id"] = (*level_)["id"];
start["name"] = (*level_)["name"];
start["objectives"] = (*level_)["objectives"];
start["next_scenario"] = (*level_)["next_scenario"];
start["music"] = (*level_)["music"];
//write out the current state of the map
start["map_data"] = map_.write();
}
void turn_info::toggle_grid()
{
preferences::set_grid(!preferences::grid());
@ -1047,6 +1122,9 @@ void turn_info::status_table()
<< string_table["units"] << "," << string_table["upkeep"] << ","
<< string_table["income"];
if(game_config::debug)
heading << "," << string_table["gold"];
items.push_back(heading.str());
//if the player is under shroud or fog, they don't get to see
@ -1069,6 +1147,9 @@ void turn_info::status_table()
<< data.units << "," << data.upkeep << ","
<< (data.net_income < 0 ? "#":"") << data.net_income;
if(game_config::debug)
str << "," << teams_[n].gold();
items.push_back(str.str());
}
@ -1208,7 +1289,8 @@ void turn_info::recall()
state_of_game_.available_units.begin();
unit != state_of_game_.available_units.end(); ++unit) {
std::stringstream option;
option << unit->type().language_name() << ","
const std::string& description = unit->description().empty() ? "-" : unit->description();
option << unit->type().language_name() << "," << description << ","
<< string_table["level"] << ": "
<< unit->type().level() << ","
<< string_table["xp"] << ": "

View file

@ -71,6 +71,8 @@ public:
private:
void write_game_snapshot(config& cfg) const;
void cycle_units();
void end_turn();
void goto_leader();

View file

@ -359,9 +359,10 @@ void show_preferences_dialog(display& disp)
const int height = 400;
//make sure that the frame buffer is restored to its original state
//when the dialog closes
//when the dialog closes. Not const, because we might want to cancel
//it in the case of video mode changes
SDL_Rect dialog_rect = {xpos-10,ypos-10,width+20,height+20};
const surface_restorer restorer(disp.video().getSurface(),dialog_rect);
surface_restorer restorer(disp.video().getSurface(),dialog_rect);
SDL_Rect clip_rect = {0,0,disp.x(),disp.y()};
SDL_Rect title_rect = font::draw_text(NULL,clip_rect,16,font::NORMAL_COLOUR,
@ -472,10 +473,9 @@ void show_preferences_dialog(display& disp)
break;
}
const double new_music=music_slider.process(mousex,mousey,left_button);
const double new_sound=sound_slider.process(mousex,mousey,left_button);
const double new_scroll =
scroll_slider.process(mousex,mousey,left_button);
const double new_music = music_slider.process(mousex,mousey,left_button);
const double new_sound = sound_slider.process(mousex,mousey,left_button);
const double new_scroll = scroll_slider.process(mousex,mousey,left_button);
if(new_sound >= 0.0) {
set_sound_volume(new_sound);
@ -490,6 +490,9 @@ void show_preferences_dialog(display& disp)
}
if(fullscreen_button.process(mousex,mousey,left_button)) {
//the underlying frame buffer is changing, so cancel
//the surface restorer restoring the frame buffer state
restorer.cancel();
set_fullscreen(fullscreen_button.checked());
redraw_all = true;
}
@ -536,7 +539,12 @@ void show_preferences_dialog(display& disp)
}
if(resolution_button.process(mousex,mousey,left_button)) {
show_video_mode_dialog(disp);
const bool mode_changed = show_video_mode_dialog(disp);
if(mode_changed) {
//the underlying frame buffer is changing, so cancel
//the surface restorer restoring the frame buffer state
restorer.cancel();
}
break;
}
@ -548,8 +556,7 @@ void show_preferences_dialog(display& disp)
set_turn_dialog(turn_dialog_button.checked());
}
if (hotkeys_button.
process (mousex, mousey, left_button))
if (hotkeys_button.process (mousex, mousey, left_button))
{
show_hotkeys_dialog (disp);
break;
@ -562,7 +569,7 @@ void show_preferences_dialog(display& disp)
}
}
void show_video_mode_dialog(display& disp)
bool show_video_mode_dialog(display& disp)
{
const events::resize_lock prevent_resizing;
@ -580,7 +587,7 @@ void show_video_mode_dialog(display& disp)
else
std::cerr << "No modes supported\n";
gui::show_dialog(disp,NULL,"",string_table["video_mode_unavailable"]);
return;
return false;
}
for(int i = 0; modes[i] != NULL; ++i) {
@ -599,7 +606,7 @@ void show_video_mode_dialog(display& disp)
if(resolutions.size() < 2) {
gui::show_dialog(disp,NULL,"",string_table["video_mode_unavailable"]);
return;
return false;
}
const int result = gui::show_dialog(disp,NULL,"",
@ -607,6 +614,9 @@ void show_video_mode_dialog(display& disp)
gui::MESSAGE,&options);
if(size_t(result) < resolutions.size()) {
set_resolution(resolutions[result]);
return true;
} else {
return false;
}
}

View file

@ -82,7 +82,7 @@ namespace preferences {
std::string client_type();
void show_preferences_dialog(display& disp);
void show_video_mode_dialog(display& disp);
bool show_video_mode_dialog(display& disp);
void show_hotkeys_dialog (display & disp);
}

View file

@ -105,14 +105,16 @@ bool replay::skipping() const
return skip_ != 0;
}
void replay::save_game(game_data& data, const std::string& label)
void replay::save_game(game_data& data, const std::string& label, const config& start_pos)
{
saveInfo_.starting_pos = start_pos;
saveInfo_.replay_data = cfg_;
saveInfo_.label = label;
::save_game(saveInfo_);
saveInfo_.replay_data = config();
saveInfo_.starting_pos = config();
}
void replay::add_recruit(int value, const gamemap::location& loc)
@ -216,6 +218,11 @@ void replay::end_turn()
cmd->add_child("end_turn");
}
void replay::speak(const config& cfg)
{
add_command()->add_child("speak") = cfg;
}
config replay::get_data_range(int cmd_start, int cmd_end)
{
log_scope("get_data_range\n");
@ -240,7 +247,7 @@ void replay::undo()
}
}
const config::child_list& replay::commands()
const config::child_list& replay::commands() const
{
return cfg_.get_children("command");
}
@ -321,6 +328,17 @@ config* replay::get_next_action()
return current_;
}
bool replay::at_end() const
{
return pos_ >= commands().size();
}
void replay::set_to_end()
{
pos_ = commands().size();
current_ = NULL;
}
void replay::clear()
{
cfg_ = config();
@ -362,25 +380,22 @@ bool do_replay(display& disp, const gamemap& map, const game_data& gameinfo,
for(;;) {
config* const cfg = replayer.get_next_action();
std::map<std::string,std::vector<config*> >::iterator it;
config* child;
//if we are expecting promotions here
if(advancing_units.empty() == false) {
if(cfg == NULL ||
(it = cfg->children.find("choose")) == cfg->children.end()) {
if(cfg == NULL || (child = cfg->child("choose")) == NULL) {
std::cerr << "promotion expected, but none found\n";
throw replay::error();
}
const std::map<gamemap::location,unit>::iterator u =
units.find(advancing_units.front());
const std::map<gamemap::location,unit>::iterator u = units.find(advancing_units.front());
assert(u != units.end());
const std::string& num = it->second.front()->values["value"];
const std::string& num = (*child)["value"];
const int val = atoi(num.c_str());
const std::vector<std::string>& options =
u->second.type().advances_to();
const std::vector<std::string>& options = u->second.type().advances_to();
if(size_t(val) >= options.size()) {
std::cerr << "illegal advancement type\n";
throw replay::error();
@ -398,31 +413,28 @@ bool do_replay(display& disp, const gamemap& map, const game_data& gameinfo,
}
//if there is an end turn directive
else if(cfg->children.find("end_turn") != cfg->children.end()) {
else if(cfg->child("end_turn") != NULL) {
replayer.next_skip();
return true;
}
else if((it = cfg->children.find("recruit")) != cfg->children.end()) {
assert(!it->second.empty());
const std::string& recruit_num=it->second.front()->values["value"];
else if((child = cfg->child("recruit")) != NULL) {
const std::string& recruit_num = (*child)["value"];
const int val = atoi(recruit_num.c_str());
const gamemap::location loc(*(it->second.front()));
const gamemap::location loc(*child);
const std::set<std::string>& recruits = current_team.recruits();
std::set<std::string>::const_iterator itor = recruits.begin();
std::advance(itor,val);
const std::map<std::string,unit_type>::const_iterator u_type =
gameinfo.unit_types.find(*itor);
const std::map<std::string,unit_type>::const_iterator u_type = gameinfo.unit_types.find(*itor);
if(u_type == gameinfo.unit_types.end()) {
std::cerr << "recruiting illegal unit\n";
throw replay::error();
}
unit new_unit(&(u_type->second),team_num,true);
const std::string& res =
recruit_unit(map,team_num,units,new_unit,loc);
const std::string& res = recruit_unit(map,team_num,units,new_unit,loc);
if(!res.empty()) {
std::cerr << "cannot recruit unit: " << res << "\n";
throw replay::error();
@ -431,36 +443,35 @@ bool do_replay(display& disp, const gamemap& map, const game_data& gameinfo,
current_team.spend_gold(u_type->second.cost());
}
else if((it = cfg->children.find("recall")) != cfg->children.end()) {
else if((child = cfg->child("recall")) != NULL) {
std::sort(state_of_game.available_units.begin(),
state_of_game.available_units.end(),
compare_unit_values());
assert(!it->second.empty());
const std::string recall_num = it->second.front()->values["value"];
const std::string recall_num = (*child)["value"];
const int val = atoi(recall_num.c_str());
const gamemap::location loc(*(it->second.front()));
const gamemap::location loc(*child);
recruit_unit(map,team_num,units,
state_of_game.available_units[val],loc);
state_of_game.available_units.erase(
state_of_game.available_units.begin()+val);
recruit_unit(map,team_num,units,state_of_game.available_units[val],loc);
state_of_game.available_units.erase(state_of_game.available_units.begin()+val);
current_team.spend_gold(game_config::recall_cost);
}
else if((it = cfg->children.find("move")) != cfg->children.end()) {
assert(!it->second.empty());
else if((child = cfg->child("move")) != NULL) {
config* const move = it->second.front();
const config* const destination = child->child("destination");
const config* const source = child->child("source");
assert(move->child("destination") != NULL);
assert(move->child("source") != NULL);
if(destination == NULL || source == NULL) {
std::cerr << "no destination/source found in movement\n";
throw replay::error();
}
const gamemap::location src(*(move->child("source")));
const gamemap::location dst(*(move->child("destination")));
const gamemap::location src(*source);
const gamemap::location dst(*destination);
const std::map<gamemap::location,unit>::iterator u=units.find(src);
const std::map<gamemap::location,unit>::iterator u = units.find(src);
if(u == units.end()) {
std::cerr << "unfound location for source of movement: "
<< (src.x+1) << "," << (src.y+1) << "-"
@ -526,21 +537,23 @@ bool do_replay(display& disp, const gamemap& map, const game_data& gameinfo,
clear_shroud(disp,map,gameinfo,units,teams,team_num-1);
}
else if((it = cfg->children.find("attack")) != cfg->children.end()) {
assert(!it->second.empty());
else if((child = cfg->child("attack")) != NULL) {
config* const move = it->second.front();
const config* const destination = child->child("destination");
const config* const source = child->child("source");
assert(move->child("destination") != NULL);
assert(move->child("source") != NULL);
if(destination == NULL || source == NULL) {
std::cerr << "no destination/source found in attack\n";
throw replay::error();
}
const gamemap::location src(*(move->child("source")));
const gamemap::location dst(*(move->child("destination")));
const gamemap::location src(*source);
const gamemap::location dst(*destination);
const std::string& weapon = move->values["weapon"];
const std::string& weapon = (*child)["weapon"];
const int weapon_num = atoi(weapon.c_str());
std::map<gamemap::location,unit>::iterator u=units.find(src);
std::map<gamemap::location,unit>::iterator u = units.find(src);
if(u == units.end()) {
std::cerr << "unfound location for source of attack\n";
throw replay::error();
@ -582,6 +595,8 @@ bool do_replay(display& disp, const gamemap& map, const game_data& gameinfo,
tgt->second.type().advances_to().empty() == false) {
advancing_units.push_back(tgt->first);
}
} else if((child = cfg->child("speak")) != NULL) {
dialogs::unit_speak(*child,disp,units);
} else {
std::cerr << "unrecognized action: '" << cfg->write() << "'\n";
throw replay::error();

View file

@ -37,7 +37,7 @@ public:
void next_skip();
bool skipping() const;
void save_game(game_data& data, const std::string& label);
void save_game(game_data& data, const std::string& label, const config& start_pos);
void add_recruit(int unit_index, const gamemap::location& loc);
void add_recall(int unit_index, const gamemap::location& loc);
@ -47,6 +47,8 @@ public:
void choose_option(int index);
void end_turn();
void speak(const config& cfg);
config get_data_range(int cmd_start, int cmd_end);
config get_last_turn(int num_turns=1);
@ -59,6 +61,9 @@ public:
void start_replay();
config* get_next_action();
bool at_end() const;
void set_to_end();
void clear();
bool empty();
@ -77,7 +82,7 @@ private:
void add_value(const std::string& type, int value);
const config::child_list& commands();
const config::child_list& commands() const;
config* add_command();
config cfg_;
unsigned int pos_;

View file

@ -120,7 +120,7 @@ SDL_Surface* get_surface_portion(SDL_Surface* src, SDL_Rect& area)
/* Rotates 8-, 16-, and 32-bit sprites. 24-bit sprites aren't handled; you
* must convert to one of these color depths before calling this function.
* */
#ifdef WIN32
#if (defined(_WIN32) || defined(__APPLE__))
#define tanf(value) (float)tan(value)
#define sinf(value) (float)sin(value)
#define cosf(value) (float)cos(value)
@ -461,11 +461,18 @@ surface_restorer::~surface_restorer()
void surface_restorer::restore()
{
::SDL_BlitSurface(surface_,NULL,target_,&rect_);
update_rect(rect_);
if(surface_ != NULL) {
::SDL_BlitSurface(surface_,NULL,target_,&rect_);
update_rect(rect_);
}
}
void surface_restorer::update()
{
surface_.assign(::get_surface_portion(target_,rect_));
}
void surface_restorer::cancel()
{
surface_.assign(NULL);
}

View file

@ -131,6 +131,7 @@ struct surface_restorer
void restore();
void update();
void cancel();
private:
SDL_Surface* target_;

View file

@ -328,7 +328,7 @@ void run_server()
}
}
int main()
int main(int argc, char** argv)
{
try {
run_server();
@ -336,4 +336,6 @@ int main()
std::cerr << "error starting server: " << e.message << "\n";
return -1;
}
return 0;
}

View file

@ -192,6 +192,7 @@ int show_dialog(display& disp, SDL_Surface* image,
if(disp.update_locked())
return -1;
const events::event_context dialog_events_context;
const dialog_manager manager;
const events::resize_lock prevent_resizing;
@ -221,8 +222,8 @@ int show_dialog(display& disp, SDL_Surface* image,
text_widget_width =
font::draw_text(NULL, clipRect, message_font_size,
font::NORMAL_COLOUR, text_widget_label, 0, 0, NULL).w +
text_widget.width();
text_widget_height = text_widget.height() + 6;
text_widget.location().w;
text_widget_height = text_widget.location().h + 6;
}
menu menu_(disp,menu_items,type == MESSAGE);
@ -436,10 +437,10 @@ int show_dialog(display& disp, SDL_Surface* image,
const int text_widget_y = yloc+top_padding+image_h-6+text_size.h+menu_hpadding;
if(use_textbox) {
text_widget.set_location(xloc + left_padding +
text_widget_width - text_widget.width(),
text_widget.set_position(xloc + left_padding +
text_widget_width - text_widget.location().w,
text_widget_y);
text_widget.draw();
events::raise_draw_event();
font::draw_text(&disp, clipRect, message_font_size,
font::NORMAL_COLOUR, text_widget_label,
xloc + left_padding,text_widget_y);
@ -448,7 +449,7 @@ int show_dialog(display& disp, SDL_Surface* image,
//set the position of any tick boxes. they go right below the menu, slammed against
//the right side of the dialog
if(options != NULL) {
int options_y = text_widget_y + (use_textbox ? text_widget.height() : 0) + menu_.height() + button_height_padding + menu_hpadding;
int options_y = text_widget_y + (use_textbox ? text_widget.location().h : 0) + menu_.height() + button_height_padding + menu_hpadding;
for(size_t i = 0; i != check_buttons.size(); ++i) {
check_buttons[i].set_x(xloc + total_width - padding_width - check_buttons[i].width());
check_buttons[i].set_y(options_y);
@ -565,10 +566,8 @@ int show_dialog(display& disp, SDL_Surface* image,
page_up = new_page_up;
page_down = new_page_down;
if(use_textbox) {
text_widget.process();
}
events::raise_process_event();
events::raise_draw_event();
if(buttons.empty() && (new_left_button && !left_button ||
new_right_button && !right_button) ||
@ -578,7 +577,7 @@ int show_dialog(display& disp, SDL_Surface* image,
left_button = new_left_button;
right_button = new_right_button;
key_down = new_key_down;
key_down = new_key_down;
for(std::vector<button>::iterator button_it = buttons.begin();
button_it != buttons.end(); ++button_it) {
@ -625,7 +624,7 @@ TITLE_RESULT show_title(display& screen)
{
const events::resize_lock prevent_resizing;
const scoped_sdl_surface title_surface(image::get_image("title.png",image::UNSCALED));
const scoped_sdl_surface title_surface(image::get_image(game_config::game_title,image::UNSCALED));
if(title_surface == NULL) {
std::cerr << "Could not find title image 'title.png'\n";

View file

@ -18,12 +18,18 @@
#include <algorithm>
#include <cstdlib>
#include <sstream>
team::target::target(const config& cfg)
: criteria(cfg), value(atof(cfg["value"].c_str()))
{
}
void team::target::write(config& cfg) const
{
cfg = criteria;
}
team::team_info::team_info(const config& cfg)
{
gold = cfg["gold"];
@ -106,11 +112,111 @@ team::team_info::team_info(const config& cfg)
music = cfg["music"];
}
void team::team_info::write(config& cfg) const
{
cfg["gold"] = gold;
cfg["income"] = income;
cfg["name"] = name;
char buf[50];
sprintf(buf,"%d",income_per_village);
cfg["village_gold"] = buf;
sprintf(buf,"%f",aggression);
cfg["aggression"] = buf;
std::stringstream enemies_str;
for(std::vector<int>::const_iterator en = enemies.begin(); en != enemies.end(); ++en) {
enemies_str << *en;
if(en+1 != enemies.end())
enemies_str << ",";
}
cfg["enemy"] = enemies_str.str();
switch(controller) {
case AI: cfg["controller"] = "ai"; break;
case HUMAN: cfg["controller"] = "human"; break;
case NETWORK: cfg["controller"] = "network"; break;
default: assert(false);
}
sprintf(buf,"%d",villages_per_scout);
cfg["villages_per_scout"] = buf;
sprintf(buf,"%f",leader_value);
cfg["leader_value"] = buf;
sprintf(buf,"%f",village_value);
cfg["village_value"] = buf;
for(std::vector<target>::const_iterator tg = targets.begin(); tg != targets.end(); ++tg) {
tg->write(cfg.add_child("target"));
}
std::stringstream can_recruit_str;
for(std::set<std::string>::const_iterator cr = can_recruit.begin(); cr != can_recruit.end(); ++cr) {
if(cr != can_recruit.begin())
can_recruit_str << ",";
can_recruit_str << *cr;
}
cfg["recruit"] = can_recruit_str.str();
std::stringstream recruit_pattern_str;
for(std::vector<std::string>::const_iterator p = recruitment_pattern.begin(); p != recruitment_pattern.end(); ++p) {
if(p != recruitment_pattern.begin())
recruit_pattern_str << ",";
recruit_pattern_str << *p;
}
cfg["recruitment_pattern"] = recruit_pattern_str.str();
cfg["shroud"] = use_shroud ? "yes" : "no";
cfg["fog"] = use_fog ? "yes" : "no";
if(music.empty() == false)
cfg["music"] = music;
}
team::team(const config& cfg, int gold) : gold_(gold), info_(cfg)
{
//gold is the maximum of 'gold' and what is given in the config file
if(info_.gold.empty() == false)
gold_ = maximum(gold,::atoi(info_.gold.c_str()));
//load in the villages the side controls at the start
const config::child_list& villages = cfg.get_children("village");
for(config::child_list::const_iterator v = villages.begin(); v != villages.end(); ++v) {
towers_.insert(gamemap::location(**v));
}
}
void team::write(config& cfg) const
{
info_.write(cfg);
char buf[50];
sprintf(buf,"%d",gold_);
cfg["gold"] = buf;
//write village locations
for(std::set<gamemap::location>::const_iterator t = towers_.begin(); t != towers_.end(); ++t) {
t->write(cfg.add_child("village"));
}
std::stringstream shroud_str;
for(std::vector<std::vector<bool> >::const_iterator sh = shroud_.begin(); sh != shroud_.end(); ++sh) {
for(std::vector<bool>::const_iterator i = sh->begin(); i != sh->end(); ++i) {
shroud_str << (*i ? '1' : '0');
}
shroud_str << '\n';
}
cfg["shroud_data"] = shroud_str.str();
}
void team::get_tower(const gamemap::location& loc)

View file

@ -28,6 +28,7 @@ public:
struct target {
explicit target(const config& cfg);
void write(config& cfg) const;
config criteria;
double value;
};
@ -35,6 +36,7 @@ public:
struct team_info
{
team_info(const config& cfg);
void write(config& cfg) const;
std::string name;
std::string gold;
std::string income;
@ -58,6 +60,9 @@ public:
};
team(const config& cfg, int gold=100);
void write(config& cfg) const;
void get_tower(const gamemap::location&);
void lose_tower(const gamemap::location&);
const std::set<gamemap::location>& towers() const;

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