diff --git a/.travis.yml b/.travis.yml index 78aaf3648..62e60194f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,12 +7,15 @@ script: s/travis-build addons: apt: packages: + - libbsd-dev - liblua5.1-dev - libtolua-dev - libncurses5-dev - libsqlite3-dev - libxml2-dev - valgrind + - cppcheck + - shellcheck os: - linux notifications: diff --git a/CMakeLists.txt b/CMakeLists.txt index d9c15fa52..7e7311253 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,25 +1,56 @@ cmake_minimum_required(VERSION 2.8) -project (eressea-server C) -set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/Modules/" ${CMAKE_MODULE_PATH}) if (WIN32) FILE(TO_CMAKE_PATH "${CMAKE_MODULE_PATH}" CMAKE_MODULE_PATH ) FILE(TO_CMAKE_PATH "${CMAKE_PREFIX_PATH}" CMAKE_PREFIX_PATH ) endif(WIN32) +project (eressea-server C) +set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/Modules/" ${CMAKE_MODULE_PATH}) + if (MSVC) include(MSVC) +set (HAVE_STRDUP 0) +set (HAVE_STRLCAT 0) +set (HAVE_LIBBSD 0) +else (MSVC) + +INCLUDE (CheckIncludeFile) +CHECK_INCLUDE_FILE(bsd/string.h HAVE_LIBBSD) + +INCLUDE (CheckFunctionExists) +CHECK_FUNCTION_EXISTS(strdup HAVE_STRDUP) +IF (HAVE_LIBBSD) +INCLUDE (CheckLibraryExists) +CHECK_LIBRARY_EXISTS(bsd strlcat "bsd/string.h" HAVE_STRLCAT) +ELSE (HAVE_LIBBSD) +CHECK_FUNCTION_EXISTS(strlcat HAVE_STRLCAT) +ENDIF(HAVE_LIBBSD) + endif (MSVC) -find_package (SQLite3) +if (MSVC) +find_package (PDCurses) +SET(CURSES_FOUND ${PDCURSES_FOUND}) +SET(CURSES_LIBRARIES ${PDCURSES_LIBRARY}) +SET(CURSES_INCLUDE_DIR ${PDCURSES_INCLUDE_DIR}) +else (MSVC) find_package (Curses) -find_package (LibXml2) +endif (MSVC) + +if (ERESSEA_DB STREQUAL "db") +find_package (BerkeleyDB REQUIRED QUIET) +else() +find_package (SQLite3 REQUIRED QUIET) +endif() + +find_package (LibXml2 REQUIRED) find_package (ToLua REQUIRED) if (TOLUA_FOUND) -if (${TOLUA_VERSION_STRING} VERSION_GREATER "5.2") +if (${TOLUA_VERSION_STRING} VERSION_EQUAL "5.2") find_package (Lua 5.2 REQUIRED) -elseif (${TOLUA_VERSION_STRING} VERSION_GREATER "5.1") -find_package (Lua 5.1 REQUIRED) +else () +find_package (Lua51 REQUIRED) endif() endif(TOLUA_FOUND) @@ -39,3 +70,4 @@ install(DIRECTORY scripts DESTINATION ${CMAKE_INSTALL_PREFIX} FILES_MATCHING PAT install(DIRECTORY lunit DESTINATION ${CMAKE_INSTALL_PREFIX} FILES_MATCHING PATTERN "*.lua") install(DIRECTORY share DESTINATION ${CMAKE_INSTALL_PREFIX}) + diff --git a/cmake/Modules/FindBerkeleyDB.cmake b/cmake/Modules/FindBerkeleyDB.cmake new file mode 100644 index 000000000..88b0621fe --- /dev/null +++ b/cmake/Modules/FindBerkeleyDB.cmake @@ -0,0 +1,50 @@ +# -*- cmake -*- + +# - Find BerkeleyDB +# Find the BerkeleyDB includes and library +# This module defines +# DB_INCLUDE_DIR, where to find db.h, etc. +# DB_LIBRARIES, the libraries needed to use BerkeleyDB. +# DB_FOUND, If false, do not try to use BerkeleyDB. +# also defined, but not for general use are +# DB_LIBRARY, where to find the BerkeleyDB library. + +FIND_PATH(DB_INCLUDE_DIR db.h + /usr/local/include/db4 + /usr/local/include + /usr/include/db4 + /usr/include + ) + +SET(DB_NAMES ${DB_NAMES} db) +FIND_LIBRARY(DB_LIBRARY + NAMES ${DB_NAMES} + PATHS /usr/lib /usr/local/lib + ) + +IF (DB_LIBRARY AND DB_INCLUDE_DIR) + SET(DB_LIBRARIES ${DB_LIBRARY}) + SET(DB_FOUND "YES") +ELSE (DB_LIBRARY AND DB_INCLUDE_DIR) + SET(DB_FOUND "NO") +ENDIF (DB_LIBRARY AND DB_INCLUDE_DIR) + + +IF (DB_FOUND) + IF (NOT DB_FIND_QUIETLY) + MESSAGE(STATUS "Found BerkeleyDB: ${DB_LIBRARIES}") + ENDIF (NOT DB_FIND_QUIETLY) +ELSE (DB_FOUND) + IF (DB_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "Could not find BerkeleyDB library") + ENDIF (DB_FIND_REQUIRED) +ENDIF (DB_FOUND) + +# Deprecated declarations. +SET (NATIVE_DB_INCLUDE_PATH ${DB_INCLUDE_DIR} ) +GET_FILENAME_COMPONENT (NATIVE_DB_LIB_PATH ${DB_LIBRARY} PATH) + +MARK_AS_ADVANCED( + DB_LIBRARY + DB_INCLUDE_DIR + ) diff --git a/cmake/Modules/FindPDCurses.cmake b/cmake/Modules/FindPDCurses.cmake new file mode 100644 index 000000000..1e326f4fd --- /dev/null +++ b/cmake/Modules/FindPDCurses.cmake @@ -0,0 +1,38 @@ +# Locate PDCurses library +# This module defines +# PDCURSES_LIBRARIES, the name of the library to link against +# PDCURSES_FOUND, if false, do not try to link to PDCurses +# PDCURSES_INCLUDE_DIR, where to find curses.h + +FIND_PATH(PDCURSES_INCLUDE_DIR curses.h + HINTS + $ENV{PDCURSESDIR} + PATH_SUFFIXES include/pdcurses include) + +FIND_LIBRARY(PDCURSES_LIBRARY + NAMES pdcurses + HINTS + $ENV{PDCURSESDIR} + PATH_SUFFIXES lib64 lib) + +FIND_LIBRARY(PDCURSES_PANEL_LIBRARY + NAMES panel + HINTS + $ENV{PDCURSESDIR} + PATH_SUFFIXES lib64 lib) + +IF(PDCURSES_LIBRARY) + SET(PDCURSES_LIBRARIES ${PDCURSES_LIBRARY}) + IF(PDCURSES_PANEL_LIBRARY) + SET(PDCURSES_LIBRARIES ${PDCURSES_LIBRARIES} ${PDCURSES_PANEL_LIBRARY}) + ENDIF(PDCURSES_PANEL_LIBRARY) +ENDIF(PDCURSES_LIBRARY) + +SET(PDCURSES_FOUND "NO") +IF(PDCURSES_INCLUDE_DIR AND PDCURSES_LIBRARY) +# message(STATUS "Found PDCurses library: ${PDCURSES_LIBRARIES}") + # Set the final string here so the GUI reflects the final state. + SET(PDCURSES_LIBRARIES PDCURSES_LIBRARY} CACHE STRING "Where the PDCurses Library can be found") + + SET(PDCURSES_FOUND "YES") +ENDIF(PDCURSES_INCLUDE_DIR AND PDCURSES_LIBRARY) diff --git a/conf/e2/config.json b/conf/e2/config.json index 0c85b316b..5d29cd1f5 100644 --- a/conf/e2/config.json +++ b/conf/e2/config.json @@ -13,7 +13,12 @@ "game.id" : 2, "orders.default": "work", "NewbieImmunity": 8, - "modules.wormholes": true, + "modules.market": false, + "modules.astralspace": true, + "modules.wormhole": true, + "modules.iceberg": true, + "modules.volcano": true, + "monsters.spawn.chance": 50, "entertain.base": 0, "entertain.perlevel": 20, "taxing.perlevel": 20, diff --git a/conf/e3/config.json b/conf/e3/config.json index b70d415a7..f3bddfdc0 100644 --- a/conf/e3/config.json +++ b/conf/e3/config.json @@ -32,8 +32,10 @@ "database.gameid": 7, "NewbieImmunity": 4, "modules.astralspace": false, - "modules.wormholes": false, - "modules.markets": true, + "modules.wormhole": false, + "modules.market": true, + "modules.iceberg": false, + "modules.volcano": true, "magic.regeneration": 0.75, "magic.power": 0.5, "resource.factor": 0.25, @@ -46,8 +48,8 @@ "healing.forest": 2.0, "hunger.long": false, "hunger.damage": "1d9+9", - "hunger.demons.skill": true, - "hunger.demons.peasant_tolerance": true, + "hunger.demon.skills": true, + "hunger.demon.peasant_tolerance": true, "init_spells": 0, "recruit.allow_merge": true, "study.expensivemigrants": true, @@ -63,6 +65,7 @@ "rules.stealth.anon_battle": false, "rules.check_overload": false, "rules.combat.goblinbonus": 3, + "rules.ship.damage_drift": 0.0, "rules.alliances": true, "rules.combat.herospeed": 3, "rules.combat.demon_vampire": 5, diff --git a/conf/eressea.ini b/conf/eressea.ini index c745631ad..17547f8f9 100644 --- a/conf/eressea.ini +++ b/conf/eressea.ini @@ -1,10 +1,9 @@ [game] -email = eressea-server@kn-bremen.de +email = eressea-server@example.com sender = Eressea Server name = Eressea report = reports verbose = 0 -lomem = 0 memcheck = 0 locales = de,en diff --git a/process/Makefile b/process/Makefile new file mode 100644 index 000000000..8edfed0b8 --- /dev/null +++ b/process/Makefile @@ -0,0 +1,6 @@ +SCRIPTS=compress.sh send-bz2-report send-zip-report create-orders \ +run-turn sendreports.sh +IGNORE=sendreport.sh + +shellcheck: $(SCRIPTS) + shellcheck $(SCRIPTS) diff --git a/process/compress.sh b/process/compress.sh index 116b3d061..4c0147978 100755 --- a/process/compress.sh +++ b/process/compress.sh @@ -1,24 +1,25 @@ #!/bin/bash -if [ -z $ERESSEA ]; then +if [ -z "$ERESSEA" ]; then echo "You need to define the \$ERESSEA environment variable to run $0" exit -2 fi -GAME=$ERESSEA/game-$1 -GAME_NAME=$(grep -w name $GAME/eressea.ini | sed 's/.*=\s*//') +GAME="$ERESSEA/game-$1" +GAME_NAME=$(grep -w name "$GAME/eressea.ini" | sed 's/.*=\s*//') TURN=$2 -if [ -z $TURN ] +if [ -z "$TURN" ] then - TURN=`cat $GAME/turn` + TURN=$(cat "$GAME/turn") fi -if [ ! -d $GAME/reports ]; then +if [ ! -d "$GAME/reports" ]; then echo "cannot find reports directory in $GAME" exit -1 fi -cd $GAME/reports -$ERESSEA/server/bin/compress.py $TURN "$GAME_NAME" -cd - +cd "$GAME/reports" || exit +"$ERESSEA/server/bin/compress.py" "$TURN" "$GAME_NAME" +cd - || exit + diff --git a/process/create-orders b/process/create-orders index 707a89737..4740dec2f 100755 --- a/process/create-orders +++ b/process/create-orders @@ -3,17 +3,17 @@ GAME=$1 TURN=$2 -if [ ! -d $ERESSEA/game-$GAME ] ; then +if [ ! -d "$ERESSEA/game-$GAME" ] ; then echo "No such game: $GAME" exit 1 fi -cd $ERESSEA/game-$GAME +cd "$ERESSEA/game-$GAME" || exit -if [ -d orders.dir.$TURN ]; then +if [ -d "orders.dir.$TURN" ]; then echo "orders.dir.$TURN already exists" else - mv orders.dir orders.dir.$TURN + mv orders.dir "orders.dir.$TURN" mkdir -p orders.dir fi find "orders.dir.$TURN" -maxdepth 1 -type f -printf "%T+\t%p\n" | sort | cut -f2 | while read -r diff --git a/process/run-turn b/process/run-turn index 1690e496e..bb12976c1 100755 --- a/process/run-turn +++ b/process/run-turn @@ -1,17 +1,17 @@ #!/bin/sh -GAME=$1 -TURN=$2 +GAME="$1" +TURN="$2" -if [ ! -d $ERESSEA/game-$GAME ] ; then +if [ ! -d "$ERESSEA/game-$GAME" ] ; then echo "No such game: $GAME" exit 1 fi -cd $ERESSEA/game-$GAME +cd "$ERESSEA/game-$GAME" || exit echo "running turn $TURN, game $GAME" -$ERESSEA/server/bin/eressea -t $TURN run-turn.lua +"$ERESSEA/server/bin/eressea" -t "$TURN" run-turn.lua mkdir -p log -ln -f eressea.log log/eressea.log.$TURN +ln -f eressea.log "log/eressea.log.$TURN" diff --git a/process/send-bz2-report b/process/send-bz2-report index f4b2ad6ea..c9fb87840 100755 --- a/process/send-bz2-report +++ b/process/send-bz2-report @@ -1,13 +1,12 @@ #!/bin/bash -if [ -z $ERESSEA ]; then - ERESSEA=`echo $PWD |sed -e 's/\/game.*//'` +if [ -z "$ERESSEA" ]; then + ERESSEA=$(echo "$PWD" |sed -e 's/\/game.*//') echo "Assuming that ERESSEA=$ERESSEA" fi if [ ! -f reports.txt ]; then echo "need to run $0 from the report direcory" exit -2 fi -source $HOME/bin/functions.sh TEMPLATE=report-mail.txt if [ "$1" == "-Lde" ] @@ -16,7 +15,7 @@ then shift fi -if [ "$1" == "-Lde" ] +if [ "$1" == "-Len" ] then TEMPLATE=report-mail.en.txt shift @@ -26,4 +25,6 @@ addr=$1 subj=$2 shift 2 -cat $ERESSEA/server/etc/$TEMPLATE | mutt -F $ERESSEA/etc/muttrc -s "$subj" -a $* -- $addr +mutt -F "$ERESSEA/etc/muttrc" -s "$subj" -a "$@" -- "$addr" \ + < "$ERESSEA/server/etc/$TEMPLATE" + diff --git a/process/send-zip-report b/process/send-zip-report index 6ea2ea8e7..89f742b82 100755 --- a/process/send-zip-report +++ b/process/send-zip-report @@ -1,6 +1,7 @@ #!/bin/bash -if [ -z $ERESSEA ]; then - ERESSEA=`echo $PWD |sed -e 's/\/game.*//'` + +if [ -z "$ERESSEA" ]; then + ERESSEA=$(echo "$PWD" |sed -e 's/\/game.*//') echo "Assuming that ERESSEA=$ERESSEA" fi if [ ! -f reports.txt ]; then @@ -9,7 +10,7 @@ if [ ! -f reports.txt ]; then fi PWD=$(pwd) -GAME=$(dirname $PWD) +GAME=$(dirname "$PWD") TEMPLATE=report-mail.txt if [ "$1" == "-Lde" ] @@ -24,13 +25,13 @@ then shift fi -if [ -e $GAME/$TEMPLATE ]; then -TEMPLATE=$GAME/$TEMPLATE +if [ -e "$GAME/$TEMPLATE" ]; then +TEMPLATE="$GAME/$TEMPLATE" else -TEMPLATE=$ERESSEA/server/etc/$TEMPLATE +TEMPLATE="$ERESSEA/server/etc/$TEMPLATE" fi -if [ ! -e $TEMPLATE ]; then +if [ ! -e "$TEMPLATE" ]; then echo "no such email template: $TEMPLATE" exit -3 fi @@ -42,8 +43,7 @@ done addr=$1 subject=$2 shift 2 -mutt -F $ERESSEA/etc/muttrc -s "$subject" -a $* -- $addr < $TEMPLATE -if [ $? -ne 0 ] ; then - echo "Sending failed for email/report: $2/$3" -fi +mutt -F "$ERESSEA/etc/muttrc" -s "$subject" -a "$@" -- "$addr" \ + < "$TEMPLATE" || echo "Sending failed for email/report: $2/$3" + diff --git a/process/sendreport.sh b/process/sendreport.sh index 93d52f0b4..be643ef56 100755 --- a/process/sendreport.sh +++ b/process/sendreport.sh @@ -1,7 +1,5 @@ #!/bin/bash -## this script takes a backup of a turn. -## usage: backup.sh if [ -z $ERESSEA ]; then echo "You have to define the \$ERESSEA environment variable to run $0" diff --git a/process/sendreports.sh b/process/sendreports.sh index c2bfa741c..d1adba943 100755 --- a/process/sendreports.sh +++ b/process/sendreports.sh @@ -3,30 +3,23 @@ ## ## Prepare the report -if [ -z $ERESSEA ]; then +if [ -z "$ERESSEA" ]; then echo "You have to define the \$ERESSEA environment variable to run $0" exit -2 fi -source $HOME/bin/functions.sh -if [ ! -z $1 ]; then - GAME=$ERESSEA/game-$1 +if [ ! -z "$1" ]; then + GAME="$ERESSEA/game-$1" else GAME=$ERESSEA fi -cd $GAME/reports || abort "could not chdir to reports directory" +cd "$GAME/reports" || exit for REPORT in *.sh do echo -n "Sending " - basename $REPORT .sh - bash $REPORT + basename "$REPORT" .sh + bash "$REPORT" done -cd - - -if [ -e $GAME/ages.sh ]; then - cd $GAME - ./ages.sh - cd - -fi +cd - || exit diff --git a/res/armor.xml b/res/armor.xml deleted file mode 100644 index f26848da2..000000000 --- a/res/armor.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - diff --git a/res/buildings.xml b/res/buildings.xml deleted file mode 100644 index 02b86d227..000000000 --- a/res/buildings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/res/core/common/items.xml b/res/core/common/items.xml index 35f9af2c5..564e9fafd 100644 --- a/res/core/common/items.xml +++ b/res/core/common/items.xml @@ -46,7 +46,7 @@ - + diff --git a/res/core/de/strings.xml b/res/core/de/strings.xml index ea4acf758..6801cbb35 100644 --- a/res/core/de/strings.xml +++ b/res/core/de/strings.xml @@ -818,6 +818,10 @@ Ereignisse + + Hinweise + Notifications + Botschaften @@ -3699,7 +3703,7 @@ Aushorchen - sound_out + Sound out Kriegsgesang @@ -7305,16 +7309,6 @@ regular spell - - Es ist Winter, und Insekten können nur in Wüsten oder mit Hilfe des Nestwärme-Tranks Personen rekrutieren. - It is winter, and insects can only recruit in deserts or with the aid of nestwarmth potions. - - - - Es ist Spätherbst, und diese Woche ist die letzte vor dem Winter, in der Insekten rekrutieren können. - It is the last week before winter in which insects can still recruit. - - Eigentümer Owner @@ -7337,8 +7331,8 @@ - eine zu %d%% vollendete Straße - a road that is %d%% complete + eine zu $percent% vollendete Straße + a road that is $percent% complete diff --git a/res/core/messages.xml b/res/core/messages.xml index 8606f0bd3..00f2da5fd 100644 --- a/res/core/messages.xml +++ b/res/core/messages.xml @@ -1,5 +1,13 @@ + + Es ist Winter, und Insekten können nur in Wüsten oder mit Hilfe des Nestwärme-Tranks Personen rekrutieren. + It is winter, and insects can only recruit in deserts or with the aid of nestwarmth potions. + + + Es ist Spätherbst, und diese Woche ist die letzte vor dem Winter, in der Insekten rekrutieren können. + It is the last week before winter in which insects can still recruit. + @@ -157,8 +165,8 @@ - Dieser Zauber verursacht einen gigantischen magischen Strudel. Der Mahlstrom wird alle Schiffe, die in seinen Sog geraten, schwer beschädigen. ($int36($id)) - This spell causes a gargantuan vortex. The maelstrom will heavily damage all ships coming into its wake. ($int36($id)) + Der Mahlstrom in dieser Region wird alle Schiffe, die in seinen Sog geraten, schwer beschädigen. ($int36($id)) + The maelstrom in this area will heavily damage all ships coming into its wake. ($int36($id)) @@ -460,7 +468,7 @@ "Die Ausrüstung von $unit($unit) scheint unsichtbar. ($int36($id))" "$unit($unit)'s equipment is invisible. ($int36($id))" - + @@ -468,7 +476,7 @@ "Die natürliche Widerstandskraft gegen Verzauberung ist gestärkt. ($int36($id))" "The magical resistance has been strengthened. ($int36($id))" - + @@ -6807,19 +6815,10 @@ + - "$unit($unit) benutzt ein $resource($item,1)." - "$unit($unit) uses a $resource($item,1)." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $resource($item,0) können nur von Ein-Personen Einheiten benutzt werden." - "$unit($unit) in $region($region): '$order($command)' - $resource($item,0) can only be used by single-person units." + "$unit($unit) benutzt $amount $resource($item,$amount)." + "$unit($unit) uses $amount $resource($item,$amount)." @@ -7061,7 +7060,7 @@ "Please send in orders for the next turn if you want to continue playing." - + diff --git a/res/core/ships.xml b/res/core/ships.xml index fc87bc3d3..33d0dc52a 100644 --- a/res/core/ships.xml +++ b/res/core/ships.xml @@ -14,7 +14,7 @@ - + diff --git a/res/core/weapons/firesword.xml b/res/core/weapons/firesword.xml index 9e8284fe6..d716e6013 100644 --- a/res/core/weapons/firesword.xml +++ b/res/core/weapons/firesword.xml @@ -1,7 +1,7 @@ - + diff --git a/res/core/weapons/mallornlance.xml b/res/core/weapons/mallornlance.xml index c67390d52..4024d4578 100644 --- a/res/core/weapons/mallornlance.xml +++ b/res/core/weapons/mallornlance.xml @@ -4,7 +4,7 @@ - + diff --git a/res/core/weapons/mallornspear.xml b/res/core/weapons/mallornspear.xml index 66d41a943..516f59540 100644 --- a/res/core/weapons/mallornspear.xml +++ b/res/core/weapons/mallornspear.xml @@ -4,7 +4,7 @@ - + diff --git a/res/core/weapons/runesword.xml b/res/core/weapons/runesword.xml index 566fe1589..1bfae2544 100644 --- a/res/core/weapons/runesword.xml +++ b/res/core/weapons/runesword.xml @@ -1,7 +1,7 @@ - + diff --git a/res/e3a/spellbooks/cerddor.xml b/res/e3a/spellbooks/cerddor.xml index 3d5f0e08e..9b6e4cd8e 100644 --- a/res/e3a/spellbooks/cerddor.xml +++ b/res/e3a/spellbooks/cerddor.xml @@ -33,4 +33,5 @@ + diff --git a/res/e3a/spellbooks/common.xml b/res/e3a/spellbooks/common.xml index 0735bc248..688a1b9ae 100644 --- a/res/e3a/spellbooks/common.xml +++ b/res/e3a/spellbooks/common.xml @@ -34,7 +34,6 @@ - diff --git a/res/e3a/spellbooks/draig.xml b/res/e3a/spellbooks/draig.xml index 34b6e7642..d97a695b3 100644 --- a/res/e3a/spellbooks/draig.xml +++ b/res/e3a/spellbooks/draig.xml @@ -29,4 +29,5 @@ + diff --git a/res/e3a/spellbooks/gray.xml b/res/e3a/spellbooks/gray.xml index 9c0035e78..78645f907 100644 --- a/res/e3a/spellbooks/gray.xml +++ b/res/e3a/spellbooks/gray.xml @@ -127,7 +127,6 @@ - diff --git a/res/e3a/spellbooks/gwyrrd.xml b/res/e3a/spellbooks/gwyrrd.xml index ac51495cf..452100ace 100644 --- a/res/e3a/spellbooks/gwyrrd.xml +++ b/res/e3a/spellbooks/gwyrrd.xml @@ -30,4 +30,5 @@ + diff --git a/res/e3a/spellbooks/illaun.xml b/res/e3a/spellbooks/illaun.xml index 129e15f21..6b89df8fa 100644 --- a/res/e3a/spellbooks/illaun.xml +++ b/res/e3a/spellbooks/illaun.xml @@ -30,4 +30,5 @@ + diff --git a/res/e3a/strings.xml b/res/e3a/strings.xml index e3c5b10ae..253501f9f 100644 --- a/res/e3a/strings.xml +++ b/res/e3a/strings.xml @@ -282,4 +282,11 @@ + + + The "Water of Life" allows living trees to be created from logs. A Knotroot and Elvendear are heated until one can just still keep one's finger in. This is then poured into a jar and allowed to cool slowly. The extract is sufficient for five trees to be grown from logs. + Das 'Wasser des Lebens' ist in der Lage, aus gefällten Baumstämmen wieder lebende Bäume zu machen. Dazu wird ein knotiger Saugwurz zusammen mit einem Elfenlieb erwärmt, so dass man gerade noch den Finger reinhalten kann. Dies gieße man in ein Gefäß und lasse es langsam abkühlen. Der Extrakt reicht um aus fünf Holzstämmen neue Bäume wachsen zu lassen. + + + diff --git a/res/e3a/weapons/mallornlance.xml b/res/e3a/weapons/mallornlance.xml index 8eb25ceb4..0c50d125a 100644 --- a/res/e3a/weapons/mallornlance.xml +++ b/res/e3a/weapons/mallornlance.xml @@ -4,7 +4,7 @@ - + diff --git a/res/eressea/races.xml b/res/eressea/races.xml index b04311cb9..cdd483851 100644 --- a/res/eressea/races.xml +++ b/res/eressea/races.xml @@ -957,7 +957,7 @@ - + diff --git a/res/herbs.xml b/res/herbs.xml deleted file mode 100644 index 69c67fe5c..000000000 --- a/res/herbs.xml +++ /dev/null @@ -1,89 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/res/luxuries.xml b/res/luxuries.xml deleted file mode 100644 index 83c187c6e..000000000 --- a/res/luxuries.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/res/ships.xml b/res/ships.xml deleted file mode 100644 index fbd6ce8e6..000000000 --- a/res/ships.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/res/weapons.xml b/res/weapons.xml deleted file mode 100644 index d0b508012..000000000 --- a/res/weapons.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/s/build b/s/build index e47ecf903..636777541 100755 --- a/s/build +++ b/s/build @@ -31,15 +31,18 @@ if [ ! -d $ROOT/$BUILD ]; then fi echo "build eressea" +CMAKE_ARGS=".." cd $ROOT/$BUILD BRANCH=$(git status -s -b | head -1 | cut -d\ -f 2 | sed 's/\..*//') if [ "$BRANCH" = "master" ] ; then VERSION=$(git describe --match 'v*.*.*' --tags | sed 's/^v//') echo "$BRANCH $VERSION" -cmake -DERESSEA_VERSION="$VERSION" .. +CMAKE_ARGS="-DERESSEA_VERSION=$VERSION ${CMAKE_ARGS}" else REV=$(git rev-parse --short HEAD) -cmake -DERESSEA_BUILDNO="$REV" .. +CMAKE_ARGS="-DERESSEA_BUILDNO=$REV $CMAKE_ARGS" fi + +cmake ${CMAKE_ARGS} make $MAKEOPTS && make test cd $OLDPWD diff --git a/s/cmake-init b/s/cmake-init index 9d529a433..5da7e985f 100755 --- a/s/cmake-init +++ b/s/cmake-init @@ -1,5 +1,20 @@ #!/bin/sh +ERESSEA_DB=sqlite +if [ -e /usr/include/db.h ] ; then +ERESSEA_DB=db +fi + +# Parse command line arguments +while [ ! -z "$1" ] ; do +if [ "$1" = "--with-db" ] ; then +ERESSEA_DB=db +elif [ "$1" = "--with-sqlite" ] ; then +ERESSEA_DB=sqlite +fi +shift 1 +done + ROOT=$(git rev-parse --show-toplevel) [ -z $BUILD ] && BUILD=Debug [ -z "$CC" ] && [ ! -z `which clang` ] && CC="clang" @@ -15,8 +30,6 @@ mkdir -p $BIN_DIR rm -f $BUILD ln -sf $BIN_DIR $BUILD -rm -f CMakeCache.txt - # use anything installed in /opt or /usr LIBRARY_PATH=/opt/lib:/opt/lib/$MACHINE:/usr/lib/$MACHINE INCLUDE_PATH=/opt/include:/usr/include @@ -30,30 +43,43 @@ if [ -d $HOME/usr ]; then fi DEST=$(dirname $ROOT)/server -ARGS=" -DCMAKE_BUILD_TYPE=$BUILD \ - -DCMAKE_LIBRARY_PATH=$LIBRARY_PATH \ - -DCMAKE_PREFIX_PATH=$PREFIX_PATH \ - -DCMAKE_INSTALL_PREFIX=$DEST" -# -DCMAKE_INCLUDE_PATH=$INCLUDE_PATH git submodule update --init +LUA_VERSION="5.2" +LUA_DIR=/usr +if [ -d /usr/include/lua5.1 ]; then + LUA_VERSION="5.1" +elif [ -d /usr/local/include/lua5.1 ]; then + export LUA_DIR=/usr/local + LUA_VERSION="5.1" +fi + +cat >| $BUILD/config.cmake <> $BUILD/config.cmake <> eressea.ini -fi + if [ $edit -eq 1 ]; then + $INIFILE eressea.ini add $1 + else + echo "[$1]" >> eressea.ini + fi } + function ini_add() { -if [ $edit -eq 1 ]; then -$INIFILE eressea.ini add $1:$2 $3 -else -echo "$2 = $3" >> eressea.ini -fi + if [ $edit -eq 1 ]; then + $INIFILE eressea.ini add $1:$2 $3 + else + echo "$2 = $3" >> eressea.ini + fi } + function ini_start() { -if [ -e eressea.ini ]; then -if [ ! -e $INIFILE ] && [ $edit -eq 1 ]; then -abort "missing editor for eressea.ini. use -n to create new file." -fi -rm -f eressea.ini -edit=0 -else -edit=0 -fi -touch eressea.ini + if [ -e eressea.ini ]; then + if [ ! -e $INIFILE ] && [ $edit -eq 1 ]; then + abort "missing editor for eressea.ini. use -n to create new file." + fi + rm -f eressea.ini + edit=0 + else + edit=0 + fi + touch eressea.ini } ini_start diff --git a/s/travis-build b/s/travis-build index 438f2ce36..a678b1de2 100755 --- a/s/travis-build +++ b/s/travis-build @@ -16,12 +16,27 @@ cd tests ./run-turn.sh } +cppcheck_tests() { + cppcheck --version + DIRS="util kernel modules races attributes triggers items tools spells" + IGNORE="" + for DIR in $DIRS ; do + IGNORE="$IGNORE -i src/$DIR" + echo "cppcheck src/$DIR" + cppcheck --quiet -Isrc -Iclibs -Istorage -IcJSON --error-exitcode=1 "src/$DIR" + done + echo "cppcheck src" + cppcheck --quiet -Isrc -Iclibs -Istorage -IcJSON --error-exitcode=1 $IGNORE src +} + set -e [ -z $BUILD ] && BUILD=Debug ; export BUILD s/cmake-init +# cppcheck_tests s/build +cd process +make cd $ROOT inifile s/runtests -V - integration_tests diff --git a/scripts/run-turn.lua b/scripts/run-turn.lua index 83d4045ac..34340d43c 100644 --- a/scripts/run-turn.lua +++ b/scripts/run-turn.lua @@ -25,20 +25,6 @@ function callbacks(rules, name, ...) end end -local function dbupdate() - update_scores() - if config.dbname then - dbname = config.basepath..'/'..config.dbname - edb = db.open(dbame) - if edb~=nil then - edb:update_factions() - edb:update_scores() - else - eressea.log.error("could not open "..dbname) - end - end -end - local function write_emails(locales) local files = {} local key @@ -143,7 +129,6 @@ function process(rules, orders) end turn_begin() - init_summary() -- run the turn: if eressea.read_orders(orders) ~= 0 then @@ -161,7 +146,7 @@ function process(rules, orders) turn_end() -- ageing, etc. write_files(config.locales) - dbupdate() + update_scores() file = '' .. get_turn() .. '.dat' if eressea.write_game(file)~=0 then diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua index 2f10b3e8a..b77606266 100644 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -121,9 +121,11 @@ function test_fleeing_units_can_be_transported() u1.number = 100 u1:add_order("ATTACKIEREN " .. itoa36(u2.id)) u2.number = 100 + u2.name = 'Passagier' u2:add_order("FAHREN " .. itoa36(u3.id)) u2:add_order("KAEMPFE FLIEHE") u3.number = 100 + u3.name = 'Transporter' u3:add_order("KAEMPFE FLIEHE") u3:add_order("TRANSPORT " .. itoa36(u2.id)) u3:add_order("NACH O ") @@ -131,8 +133,8 @@ function test_fleeing_units_can_be_transported() u3:add_item("horse", u2.number) u3:add_order("KAEMPFE FLIEHE") process_orders() - assert_equal(u3.region.id, r1.id, "transporter did not move") - assert_equal(u2.region.id, r1.id, "transported unit did not move") + assert_equal(u3.region, r1, "transporter did not move") + assert_equal(u2.region, r1, "transported unit did not move") end function test_plane() @@ -807,7 +809,6 @@ end function test_swim_and_survive() local r = region.create(0, 0, "plain") local f = create_faction('human') - f.nam = "chaos" local u = unit.create(f, r, 1) process_orders() r.terrain = "ocean" @@ -1111,3 +1112,67 @@ function test_build_castle() assert_equal(1, u.building.size) assert_equal(u.building.name, "Burg") end + +function test_route() + local r1 = region.create(0, 0, "plain") + local r2 = region.create(1, 0, "plain") + local f = faction.create("human", "route@example.com") + local u = unit.create(f, r1, 1) + u:add_order("ROUTE O W P") + process_orders() + assert_equal("ROUTE West PAUSE Ost", u:get_order(0)) + assert_equal(r2, u.region) +end + +function test_route_horse() + local r1 = region.create(0, 0, "plain") + local r2 = region.create(1, 0, "plain") + local f = faction.create("human", "route@example.com") + local u = unit.create(f, r1, 1) + u:add_order("ROUTE O P W P") + u:add_item('horse', 1) + u:set_skill('riding', 1) + process_orders() + assert_equal("ROUTE West PAUSE Ost PAUSE", u:get_order(0)) + assert_equal(r2, u.region) +end + +function test_route_pause() + local r1 = region.create(0, 0, "plain") + local r2 = region.create(1, 0, "plain") + local f = faction.create("human", "route@example.com") + local u = unit.create(f, r1, 1) + u:add_order("ROUTE P O W") + process_orders() + assert_equal("ROUTE P O W", u:get_order(0)) + assert_equal(r1, u.region) +end + +function test_bug_2393_cart() + local r1 = region.create(0, 0, "plain") + local r2 = region.create(1, 0, "plain") + local f = faction.create("human", "cart@example.com") + local u = unit.create(f, r1, 2) + u:add_order("NACH O") + u:add_item('stone', 2) + u:add_item('horse', 2) + u:add_item('cart', 1) + process_orders() + assert_equal(r1, u.region) +end + +function test_immunity_stops_guard() + eressea.settings.set("NewbieImmunity", 2) + local f = faction.create('human') + local r = region.create(0, 0, 'plain') + local u = unit.create(f, r) + u:set_skill('polearm', 2) + u:add_item('lance', 1) + u:add_order('BEWACHE') + process_orders() + assert_equal(f.age, 1) + assert_true(not u.guard) + process_orders() + assert_equal(f.age, 2) + assert_true(u.guard) +end diff --git a/scripts/tests/e2/e2features.lua b/scripts/tests/e2/e2features.lua index 20b21ce75..2c9c42e5b 100644 --- a/scripts/tests/e2/e2features.lua +++ b/scripts/tests/e2/e2features.lua @@ -214,8 +214,8 @@ end function test_can_give_person() local r = region.create(0, 0, "plain") - local f1 = faction.create("human", "noreply@eressea.de", "de") - local f2 = faction.create("human", "noreply@eressea.de", "de") + local f1 = faction.create("human") + local f2 = faction.create("human") local u1 = unit.create(f1, r, 10) local u2 = unit.create(f2, r, 10) u1.faction.age = 10 @@ -403,3 +403,45 @@ function test_give_to_other_okay() assert_equal(1, u1.number) assert_equal(2, u2.number) end + +local function get_name(x) + return x.name .. " (" .. itoa36(x.id) .. ")" +end + +function test_faction_stealth() + local f = faction.create('human') + local f2 = faction.create('human') + local r = region.create(0, 0, 'plain') + local u = unit.create(f, r) + local u2 = unit.create(f2, r) + assert_equal(get_name(u) .. ", 1 Mensch, aggressiv.", u:show(f)) + assert_equal(get_name(u) .. ", " .. get_name(f) .. ", 1 Mensch.", u:show(f2)) + u:add_order("TARNE PARTEI NUMMER " .. itoa36(f2.id)) + process_orders() + assert_equal(get_name(u) .. ", " .. get_name(f2) .. ", 1 Mensch, aggressiv.", u:show(f)) + assert_equal(get_name(u) .. ", " .. get_name(f2) .. ", 1 Mensch.", u:show(f2)) + u:clear_orders() + u:add_order("TARNE PARTEI NUMMER") + process_orders() + assert_equal(get_name(u) .. ", 1 Mensch, aggressiv.", u:show(f)) + assert_equal(get_name(u) .. ", " .. get_name(f) .. ", 1 Mensch.", u:show(f2)) +end + +function test_faction_anonymous() + local f = faction.create('human') + local f2 = faction.create('human') + local r = region.create(0, 0, 'plain') + local u = unit.create(f, r) + local u2 = unit.create(f2, r) + assert_equal(get_name(u) .. ", 1 Mensch, aggressiv.", u:show(f)) + assert_equal(get_name(u) .. ", " .. get_name(f) .. ", 1 Mensch.", u:show(f2)) + u:add_order("TARNE PARTEI") + process_orders() + assert_equal(get_name(u) .. ", anonym, 1 Mensch, aggressiv.", u:show(f)) + assert_equal(get_name(u) .. ", anonym, 1 Mensch.", u:show(f2)) + u:clear_orders() + u:add_order("TARNE PARTEI NICHT") + process_orders() + assert_equal(get_name(u) .. ", 1 Mensch, aggressiv.", u:show(f)) + assert_equal(get_name(u) .. ", " .. get_name(f) .. ", 1 Mensch.", u:show(f2)) +end diff --git a/scripts/tests/e2/init.lua b/scripts/tests/e2/init.lua index fd2f0b423..9dd507671 100644 --- a/scripts/tests/e2/init.lua +++ b/scripts/tests/e2/init.lua @@ -1,15 +1,17 @@ +require 'tests.e2.e2features' +require 'tests.e2.insects' require 'tests.e2.spells' require 'tests.e2.buildings' require 'tests.e2.production' require 'tests.e2.adamantium' require 'tests.e2.undead' require 'tests.e2.shiplanding' -require 'tests.e2.e2features' require 'tests.e2.movement' require 'tests.e2.destroy' require 'tests.e2.guard' require 'tests.e2.stealth' require 'tests.e2.items' +require 'tests.e2.ships' require 'tests.items' require 'tests.economy' require 'tests.orders' diff --git a/scripts/tests/e2/insects.lua b/scripts/tests/e2/insects.lua new file mode 100644 index 000000000..1898e215c --- /dev/null +++ b/scripts/tests/e2/insects.lua @@ -0,0 +1,87 @@ +require "lunit" + +module("tests.e2.insects", package.seeall, lunit.testcase) + +function setup() + eressea.free_game() + eressea.settings.set("rules.food.flags", "4") + eressea.settings.set("nmr.timeout", "0") + eressea.settings.set("NewbieImmunity", "0") +end + +function test_move_to_glacier() + local r = region.create(0, 0, "plain") + local r2 = region.create(1, 0, "glacier") + local f = faction.create("insect") + local u = unit.create(f, r, 1) + + u:clear_orders() + u:add_order("NACH OST") + process_orders() + assert_equal(r, u.region) +end + +function test_sail_to_glacier() + local r = region.create(0, 0, "ocean") + local r2 = region.create(1, 0, "glacier") + local f = faction.create("insect") + local u1 = unit.create(f, r, 1, 'insect') + + u1.ship = ship.create(r, 'boat') + u1:set_skill("sailing", 10) + u1:clear_orders() + u1:add_order("NACH OST") + process_orders() + assert_equal(r, u1.region) +end + +function test_passenger_into_glacier() + local r = region.create(0, 0, "ocean") + local r2 = region.create(1, 0, "glacier") + local f = faction.create("insect") + local u1 = unit.create(f, r, 1, 'human') + local u2 = unit.create(f, r, 1, 'insect') + + u1.ship = ship.create(r, 'boat') + u1:set_skill("sailing", 10) + u1:clear_orders() + u1:add_order("NACH OST") + u2.ship = u1.ship + process_orders() + assert_equal(r2, u2.region) +end + +function test_recruit_in_winter() + local r = region.create(0, 0, "plain") + local f = faction.create("insect") + local u = unit.create(f, r, 1) + + u:add_item('money', 1000) + u:clear_orders() + u:add_order("REKRUTIERE 1") + set_turn(1010) + process_orders() + assert_equal('winter', get_season(get_turn())) + assert_equal(1, u.number) + + u:clear_orders() + u:add_order("REKRUTIERE 1") + set_turn(1011) + process_orders() + assert_equal('spring', get_season(get_turn())) + assert_equal(2, u.number) +end + +function test_recruit_in_desert() + local r = region.create(0, 0, "desert") + local f = faction.create("insect") + local u = unit.create(f, r, 1) + + u:add_item('money', 1000) + u:clear_orders() + u:add_order("REKRUTIERE 1") + set_turn(1010) + process_orders() + assert_equal('winter', get_season(get_turn())) + assert_equal(2, u.number) +end diff --git a/scripts/tests/e2/items.lua b/scripts/tests/e2/items.lua index da7b3ae8f..2f2b13e88 100644 --- a/scripts/tests/e2/items.lua +++ b/scripts/tests/e2/items.lua @@ -11,6 +11,21 @@ function setup() eressea.settings.set("magic.regeneration.enable", "0") end +function test_water_of_life() + local r = region.create(0, 0, "plain") + r:set_flag(1, false) -- no mallorn + local f = faction.create("human") + local u = unit.create(f, r, 1) + local trees = r:get_resource('sapling') + u:add_item('p2', 1) + u:add_item('log', 10) + u:add_order("BENUTZE 1 'Wasser des Lebens'") + process_orders() + assert_equal(0, u:get_item('p2')) + assert_equal(0, u:get_item('log')) + assert_equal(trees+10, r:get_resource('sapling')) +end + function test_nestwarmth_insect() local r = region.create(0, 0, "plain") local f = faction.create("insect", "noreply@eressea.de", "de") @@ -113,28 +128,31 @@ function test_speedsail() assert_equal(1, u.ship:get_curse('shipspeed')) -- effect stays forever end -function test_foolpotion() +function disable_test_foolpotion() local r = region.create(0, 0, "plain") local f = faction.create("human", "noreply@eressea.de", "de") local u = unit.create(f, r, 1) turn_begin() - u:add_item("p7", 1) + u:add_item('p7', 2) u:clear_orders() u:add_order("BENUTZEN 1 Dumpfbackenbrot 4242") turn_process() - assert_equal(1, u:get_item("p7")) + assert_equal(2, u:get_item('p7')) assert_equal(1, f:count_msg_type('feedback_unit_not_found')) local u2 = unit.create(f, r, 1) u:clear_orders() - u:add_order("BENUTZEN 1 Dumpfbackenbrot " .. itoa36(u2.id)) + u:add_order("BENUTZEN 2 Dumpfbackenbrot " .. itoa36(u2.id)) turn_process() - assert_equal(1, u:get_item("p7")) + assert_equal(2, u:get_item('p7')) assert_equal(1, f:count_msg_type('error64')) - u:set_skill("stealth", 1); + u:set_skill("stealth", 1) + u2:set_skill('crossbow', 1) turn_process() - assert_equal(0, u:get_item("p7")) + assert_equal(0, u:get_item('p7')) + assert_equal(0, u2:effect('p7')) + assert_equal(0, u2:get_skill('crossbow')) assert_equal(1, f:count_msg_type('givedumb')) turn_end() end diff --git a/scripts/tests/e2/movement.lua b/scripts/tests/e2/movement.lua index b17d369f4..fb82567af 100644 --- a/scripts/tests/e2/movement.lua +++ b/scripts/tests/e2/movement.lua @@ -111,3 +111,86 @@ function test_follow_ship() assert_equal(2, u1.region.x) assert_equal(2, u2.region.x) end + +function assert_nomove(text, u) + if text == nil then text = "" else text = text .. "; " end + local r = u.region + u:add_order("NACH O O") + process_orders() + assert_equal(r, u.region, text .. "unit should never move") +end + +function assert_capacity(text, u, silver, r1, r2, rx) + if text == nil then text = "" else text = text .. "; " end + if rx == nil then rx = r1 end + u.region = r1 + u:add_item("money", silver-u:get_item("money")) + u:add_order("NACH O O") + process_orders() + assert_equal(r2, u.region, text .. "unit should move") + + u.region = r1 + u:add_item("money", 1) + process_orders() + assert_equal(rx, u.region, text .. "unit should not move") +end + +function test_dwarf_example() + local r1 = region.create(0, 0, "plain") + local r2 = region.create(1, 0, "plain") + region.create(2, 0, "plain") + local f = faction.create("dwarf", "dwarf@example.com", "de") + local u = unit.create(f, r1, 5) + u:add_item("horse", 5) + u:add_item("cart", 2) + + -- 5 dwarves + 5 horse - 2 carts = 27 + 100 - 80 = 47.00 + assert_capacity("dwarves", u, 4700, r1, r2) + + u:set_skill("riding", 3) + assert_equal(1, u:eff_skill("riding")) + -- 5 dwarves + 5 horses + 2 carts = 327.00 + assert_capacity("riding", u, 32700, r1, r2) + +end + +function test_troll_example() + local r1 = region.create(0, 0, "plain") + local r2 = region.create(1, 0, "plain") + local r3 = region.create(2, 0, "plain") + local f = faction.create("troll", "troll@example.com", "de") + local u1 = unit.create(f, r1, 3) + + u1:add_item("cart", 1) + u1:clear_orders() + + -- 3 trolls - 1 cart = 320, but not allowed? + u1.name='XXX' + assert_nomove("3 trolls", u1) + + u1.number = 4 + + -- 4 trolls + 1 cart = 14320 + assert_capacity("1 cart", u1, 14320, r1, r2) + + + u1:add_item("horse", 4) + -- 4 horses, 4 trolls, 1 cart + assert_capacity("4 horses", u1, 22320, r1, r2) + + + u1:add_item("cart", 1) + + -- 4 horses + 4 trolls + 1 cart - 1 cart + assert_capacity("2 carts", u1, 18320, r1, r2) + + u1:set_skill("riding", 3) + assert_equal(1, u1:eff_skill("riding")) + + -- 4 horses + 4 trolls + 2 carts = 323.20 + assert_capacity("walking", u1, 32320, r1, r2) + + -- 4 horses + 2 carts - 4 trolls = 200.00 + assert_capacity("riding", u1, 20000, r1, r3, r2) + +end diff --git a/scripts/tests/e2/production.lua b/scripts/tests/e2/production.lua index 1d31011af..5eae8ec74 100644 --- a/scripts/tests/e2/production.lua +++ b/scripts/tests/e2/production.lua @@ -76,3 +76,29 @@ function test_dwarf_mining_bonus() assert_equal(20, u:get_item('iron')) assert_equal(84, r:get_resource('iron')) end + +function test_build_boat_low_skill() + local r = region.create(0, 0, "plain") + local f = faction.create("human", "build@example.com") + local u = unit.create(f, r, 1) + u:set_skill("shipcraft", 3) -- humans get +1 + u:add_item("log", 10) + u:add_order("MACHE BOOT") + process_orders() + assert_not_equal(nil, u.ship) + assert_equal(4, u.ship.size) + assert_equal(6, u:get_item('log')) +end + +function test_build_boat_high_skill() + local r = region.create(0, 0, "plain") + local f = faction.create("human", "build@example.com") + local u = unit.create(f, r, 1) + u:set_skill("shipcraft", 5) -- humans get +1 + u:add_item("log", 10) + u:add_order("MACHE BOOT") + process_orders() + assert_not_equal(nil, u.ship) + assert_equal(5, u.ship.size) + assert_equal(5, u:get_item('log')) +end diff --git a/scripts/tests/e2/ships.lua b/scripts/tests/e2/ships.lua index 351609a92..3208f0a0d 100644 --- a/scripts/tests/e2/ships.lua +++ b/scripts/tests/e2/ships.lua @@ -3,17 +3,22 @@ require "lunit" module("tests.e2.ships", package.seeall, lunit.testcase) function setup() + eressea.game.reset() + eressea.settings.set("rules.food.flags", "4") eressea.settings.set("rules.ship.damage.nocrewocean", "0") eressea.settings.set("rules.ship.damage.nocrew", "0") eressea.settings.set("rules.ship.drifting", "0") + eressea.settings.set("rules.ship.storms", "0") end function test_ship_requires_skill() local r1 = region.create(0, 0, "ocean") + assert_not_nil(r1) local r2 = region.create(1, 0, "ocean") + assert_not_nil(r2) local f = faction.create("human", "fake@eressea.de", "de") local u1 = unit.create(f, r1, 1) - u1.name = "fake" + u1.name = "fake" u1.ship = ship.create(r1, "longboat") u1:clear_orders() u1:add_order("NACH O") @@ -22,21 +27,51 @@ function test_ship_requires_skill() assert_equal(r1, u1.region) end -function no_test_ship_happy_case() +function test_ship_happy_case() local r1 = region.create(0, 0, "ocean") local r2 = region.create(1, 0, "ocean") - local f = faction.create("human", "hodor@eressea.de", "de") + local f = faction.create("human") local u1 = unit.create(f, r1, 1) local u2 = unit.create(f, r1, 1) u1.ship = ship.create(r1, "longboat") - u2.ship = u1.ship + u2.ship = u1.ship u1:clear_orders() u1:add_order("NACH O") - u1:set_skill("sailing", 1) -- cptskill = 1 - u2:set_skill("sailing", 9) -- sumskill = 10 + u1:set_skill("sailing", 1) -- cptskill = 1 + u2:set_skill("sailing", 9) -- sumskill = 10 process_orders() assert_equal(r2, u1.ship.region) assert_equal(r2, u1.region) assert_equal(r2, u2.region) end +function test_speedy_ship_slow() + local r1 = region.create(0, 0, 'ocean') + local f = faction.create("human") + local u1 = unit.create(f, r1, 1) + local u2 = unit.create(f, r1, 2) + for x = 1, 10 do + region.create(x, 0, 'ocean') + end + u1.ship = ship.create(r1, "dragonship") + u2.ship = u1.ship + u1:set_skill("sailing", 2) -- cptskill = 2^1 + u2:set_skill("sailing", 24) -- sumskill = 50 + u1:add_order("NACH O O O O O O O O O O") + process_orders() + assert_equal(5, u1.region.x) +end + +function test_speedy_ship_fast() + local r1 = region.create(0, 0, 'ocean') + local f = faction.create("human") + local u1 = unit.create(f, r1, 1) + for x = 1, 10 do + region.create(x, 0, 'ocean') + end + u1.ship = ship.create(r1, "dragonship") + u1:set_skill("sailing", 54) -- cptskill = 2*3^3 + u1:add_order("NACH O O O O O O O O O O") + process_orders() + assert_equal(8, u1.region.x) +end diff --git a/scripts/tests/e2/spells.lua b/scripts/tests/e2/spells.lua index fc1e3bc3b..deeb2798c 100644 --- a/scripts/tests/e2/spells.lua +++ b/scripts/tests/e2/spells.lua @@ -9,6 +9,7 @@ function setup() eressea.settings.set("NewbieImmunity", "0") eressea.settings.set("rules.food.flags", "4") eressea.settings.set("rules.peasants.growth.factor", "0") + eressea.settings.set("magic.fumble.enable", "0") end function test_shapeshift() @@ -102,3 +103,24 @@ function test_earn_silver() assert_equal(350, u:get_item("money")) assert_equal(0, r:get_resource("money")) end + +function test_familiar() + local r = region.create(0, 0, "mountain") + local f = faction.create("human") + local u = unit.create(f, r) + local uid = u.id + u.name = 'Hodor' + u.magic = "gwyrrd" + u.race = "elf" + u:set_skill("magic", 10) + u.aura = 200 + local err = u:add_spell("summon_familiar") + assert_equal(0, err) + u:add_order("ZAUBERE Vertrauten~rufen") + process_orders() + for u in r.units do + if u.id ~= uid then + assert_equal('Vertrauter von Hodor (' .. itoa36(uid) ..')', u.name) + end + end +end diff --git a/scripts/tests/e3/items.lua b/scripts/tests/e3/items.lua index d3b857381..1df6be85a 100644 --- a/scripts/tests/e3/items.lua +++ b/scripts/tests/e3/items.lua @@ -8,6 +8,28 @@ function setup() eressea.settings.set("NewbieImmunity", "0") end +function test_water_of_life() + local r = region.create(0, 0, "plain") + r:set_flag(1, false) -- no mallorn + local f = faction.create("human") + local u = unit.create(f, r, 1) + local trees = r:get_resource('tree') + u:add_item('p2', 1) + u:add_item('log', 10) + u:add_order("BENUTZE 1 'Wasser des Lebens'") + u:add_order("ZEIGE 'Wasser des Lebens'") + process_orders() + assert_equal(0, u:get_item('p2')) + assert_equal(5, u:get_item('log')) + trees = r:get_resource('tree')-trees + if trees~=5 then + init_reports() + write_report(f) + print(f, get_turn()) + end + assert_equal(5, trees) +end + function test_give_horses() local r = region.create(0, 0, "plain") local f = faction.create("human", "noreply@eressea.de", "de") diff --git a/scripts/tests/e3/rules.lua b/scripts/tests/e3/rules.lua index 92e02f29b..0888aa0b9 100644 --- a/scripts/tests/e3/rules.lua +++ b/scripts/tests/e3/rules.lua @@ -31,10 +31,9 @@ function setup() end function teardown() - set_rule("rules.move.owner_leave") - set_rule("rules.food.flags") - set_rule("rules.ship.drifting") - set_rule("rules.ship.storms") + for k,_ in pairs(settings) do + set_rule(k) + end end function test_calendar() @@ -1008,3 +1007,22 @@ function test_give_to_other_fails() assert_equal(2, u1.number) assert_equal(1, u2.number) end + +function test_demons_using_mallornlance() + -- bug 2392 + set_rule("skillchange.demon.up", "0") + set_rule("NewbieImmunity", "0") + local r = region.create(0, 0, "plain") + local f = faction.create('goblin') + local u = unit.create(f, r, 1, 'demon') + u:set_skill('taxation', 1) + u:set_skill('polearm', 1) + u:add_item('mallornlance', 1) + u:add_order('BEWACHE') + process_orders() + if not u.guard then + init_reports() + write_report(f) + end + assert_true(u.guard) +end diff --git a/scripts/tests/hunger.lua b/scripts/tests/hunger.lua new file mode 100644 index 000000000..a33c2208b --- /dev/null +++ b/scripts/tests/hunger.lua @@ -0,0 +1,108 @@ +require "lunit" + +module("tests.hunger", package.seeall, lunit.testcase) + +function setup() + eressea.free_game() + conf = [[{ + "races": { + "demon": { + "maintenance": 10, + "hp" : 50 + }, + "insect": { + "maintenance": 10, + "hp" : 50 + } + }, + "terrains" : { + "plain": { "flags" : [ "land", "walk" ] }, + "glacier": { "flags" : [ "arctic", "land", "walk" ] } + } + }]] + + eressea.config.reset() + eressea.config.parse(conf) + + eressea.settings.set("rules.peasants.growth.factor", "0") + eressea.settings.set("rules.peasantluck.growth.factor", "0") + eressea.settings.set("hunger.damage", "10") +end + +function test_maintenance() + local r = region.create(0, 0, "plain") + local f = faction.create("insect") + local u = unit.create(f, r, 2) + local flags = u.flags + u:add_item('money', 100) + + process_orders() + assert_equal(flags, u.flags, "should not be hungry") + assert_equal(80, u:get_item('money'), "should pay maintenance") + assert_equal(100, u.hp, "should not take damage") +end + +function test_demons_eat_peasants() + local r = region.create(0, 0, "plain") + local f = faction.create("demon") + local u = unit.create(f, r, 10) + local flags = u.flags + u:add_item('money', 120) + + r.peasants = 3 + process_orders() + assert_equal(20, u:get_item('money')) + assert_equal(2, r.peasants) + assert_equal(flags, u.flags) + assert_equal(500, u.hp) +end + +function test_demons_need_peasants() + local r = region.create(0, 0, "plain") + local f = faction.create("demon") + local u = unit.create(f, r, 1) + local flags = u.flags + u:add_item('money', 100) + + eressea.settings.set("hunger.demon.peasant_tolerance", "0") + r.peasants = 0 + process_orders() + assert_equal(90, u:get_item('money')) -- use money even if no peasants + assert_equal(flags+2048, u.flags) + assert_equal(40, u.hp) + + eressea.settings.set("hunger.demon.peasant_tolerance", "1") + u.flags = flags + u.hp = 50 + process_orders() + assert_equal(80, u:get_item('money')) -- use money even if no peasants + assert_equal(flags+2048, u.flags) + assert_equal(50, u.hp) + assert_equal(0, r.peasants) +end + +function test_insects_hunger_in_glacier() + -- bug 2389 + local r = region.create(0, 0, "plain") + local f = faction.create("insect") + local u = unit.create(f, r, 1) + local flags = u.flags + u:add_item('money', 1000) + + -- eressea.settings.set("hunger.insect.cold", "1") -- default + process_orders() + assert_equal(flags, u.flags) + assert_equal(50, u.hp) + + r.terrain = 'glacier' + process_orders() + assert_equal(flags+2048, u.flags) + assert_equal(40, u.hp) + + u.flags = u.flags-2048 + u.hp = 50 + eressea.settings.set("hunger.insect.cold", "0") + process_orders() + assert_equal(flags, u.flags) + assert_equal(50, u.hp) +end diff --git a/scripts/tests/init.lua b/scripts/tests/init.lua index baa8dbef4..c933d4e69 100644 --- a/scripts/tests/init.lua +++ b/scripts/tests/init.lua @@ -9,3 +9,4 @@ require 'tests.settings' require 'tests.study' require 'tests.laws' require 'tests.bindings' +require 'tests.hunger' diff --git a/scripts/tests/items.lua b/scripts/tests/items.lua index 5c2093953..153bfb803 100644 --- a/scripts/tests/items.lua +++ b/scripts/tests/items.lua @@ -5,48 +5,42 @@ module("tests.items", package.seeall, lunit.testcase ) function setup() eressea.free_game() eressea.settings.set("nmr.timeout", "0") + eressea.settings.set("NewbieImmunity", "0") eressea.settings.set("rules.food.flags", "4") eressea.settings.set("rules.ship.storms", "0") eressea.settings.set("rules.encounters", "0") eressea.settings.set("magic.regeneration.enable", "0") end -function test_mistletoe_okay() +function test_use_mistletoe() local r = region.create(0, 0, "plain") - local f = faction.create("human", "noreply@eressea.de", "de") + local f = faction.create("human") local u = unit.create(f, r, 1) - turn_begin() - u:add_item('mistletoe', 2) - u:clear_orders() - u:add_order("BENUTZEN 1 Mistelzweig") - assert_false(u:has_attrib('fleechance')) - turn_process() - assert_true(u:has_attrib('fleechance')) + u:add_item('mistletoe', 3) + u:add_order("BENUTZEN 2 Mistelzweig") + process_orders() + assert_equal(2, u:effect('mistletoe')) assert_equal(1, u:get_item('mistletoe')) assert_equal(1, f:count_msg_type('use_item')) - turn_end() end -function test_mistletoe_fail() +function test_mistletoe_survive() local r = region.create(0, 0, "plain") - local f = faction.create("human", "noreply@eressea.de", "de") - local u = unit.create(f, r, 1) - turn_begin() - u:add_item('mistletoe', 1) - u:clear_orders() - u:add_order("BENUTZEN 1 Mistelzweig") - assert_false(u:has_attrib('fleechance')) - u.number = 2 - turn_process() - assert_false(u:has_attrib('fleechance')) - assert_equal(1, u:get_item('mistletoe')) - assert_equal(1, f:count_msg_type('use_singleperson')) - turn_end() + local u = unit.create(faction.create("human"), r, 1) + local u2 = unit.create(faction.create("human"), r, 1) + local uno = u.id + u:add_item('mistletoe', 2) + u:add_order("BENUTZEN 2 Mistelzweig") + u2:add_order('ATTACKIERE ' .. itoa36(uno)) + process_orders() + u = get_unit(uno) + assert_not_nil(u) + assert_equal(1, u:effect('mistletoe')) end function test_dreameye() local r = region.create(0, 0, "plain") - local f = faction.create("human", "noreply@eressea.de", "de") + local f = faction.create("human") local u = unit.create(f, r, 1) u:add_item("dreameye", 2) u:clear_orders() @@ -63,7 +57,7 @@ end function test_manacrystal() local r = region.create(0, 0, "plain") - local f = faction.create("human", "noreply@eressea.de", "de") + local f = faction.create("human") local u = unit.create(f, r, 1) u:add_item("manacrystal", 2) u:clear_orders() @@ -81,7 +75,7 @@ end function test_skillpotion() local r = region.create(0, 0, "plain") - local f = faction.create("human", "noreply@eressea.de", "de") + local f = faction.create("human") local u = unit.create(f, r, 1) u:add_item("skillpotion", 2) u:clear_orders() @@ -93,7 +87,7 @@ end function test_studypotion() local r = region.create(0, 0, "plain") - local f = faction.create("human", "noreply@eressea.de", "de") + local f = faction.create("human") local u = unit.create(f, r, 1) turn_begin() u:add_item("studypotion", 2) @@ -109,7 +103,7 @@ end function test_antimagic() local r = region.create(0, 0, "plain") - local f = faction.create("human", "noreply@eressea.de", "de") + local f = faction.create("human") local u = unit.create(f, r, 1) turn_begin() @@ -129,7 +123,7 @@ end function test_ointment() local r = region.create(0, 0, "plain") - local f = faction.create("human", "noreply@eressea.de", "de") + local f = faction.create("human") local u = unit.create(f, r, 1) local hp = u.hp u.hp = 1 @@ -142,14 +136,35 @@ function test_ointment() assert_equal(hp, u.hp) end +function test_use_domore() + local r = region.create(0, 0, "plain") + local f = faction.create("human") + local u = unit.create(f, r, 1) + u:add_item("p3", 1) + u:add_order("BENUTZEN 1 Schaffenstrunk") + process_orders() + assert_equal(10, u:effect("p3")) + assert_equal(0, u:get_item("p3")) + assert_equal(1, f:count_msg_type('usepotion')) + u:clear_orders() + u:set_skill('weaponsmithing', 3) + u:add_item("iron", 2) + u:add_order("MACHEN Schwert") + process_orders() + assert_equal(9, u:effect("p3")) + assert_equal(0, u:get_item("iron")) + assert_equal(2, u:get_item("sword")) +end + function test_bloodpotion_demon() local r = region.create(0, 0, "plain") - local f = faction.create("demon", "noreply@eressea.de", "de") + local f = faction.create("demon") local u = unit.create(f, r, 1) u:add_item("peasantblood", 1) u:clear_orders() u:add_order("BENUTZEN 1 Bauernblut") process_orders() + assert_equal(100, u:effect('peasantblood')) assert_equal(0, u:get_item("peasantblood")) assert_equal(1, f:count_msg_type('usepotion')) assert_equal("demon", u.race) @@ -157,12 +172,13 @@ end function test_bloodpotion_other() local r = region.create(0, 0, "plain") - local f = faction.create("human", "noreply@eressea.de", "de") + local f = faction.create("human") local u = unit.create(f, r, 1) u:add_item("peasantblood", 1) u:clear_orders() u:add_order("BENUTZEN 1 Bauernblut") process_orders() + assert_equal(0, u:effect('peasantblood')) assert_equal(0, u:get_item("peasantblood")) assert_equal(1, f:count_msg_type('usepotion')) assert_equal("smurf", u.race) diff --git a/scripts/tests/orders.lua b/scripts/tests/orders.lua index af0919640..63abaed00 100644 --- a/scripts/tests/orders.lua +++ b/scripts/tests/orders.lua @@ -47,7 +47,8 @@ function test_give() assert_not_equal(5, u2:get_item("money")) end -function test_make_temp() +function disable_test_make_temp() + -- disabled because of TOLUA_ORDERS_CLOSURE u:add_order("MACHE TEMP 123 'Herpderp'") u:add_order("// this comment will be copied") u:add_order("ENDE") diff --git a/scripts/tests/process.lua b/scripts/tests/process.lua index 296b9d5ec..f6ea63933 100644 --- a/scripts/tests/process.lua +++ b/scripts/tests/process.lua @@ -2,15 +2,15 @@ require "lunit" module("tests.process", package.seeall, lunit.testcase) -local u, r, f,turn +local u, r, f, turn function setup() eressea.free_game() + turn = get_turn() r = region.create(0, 0, "plain") f = faction.create("human", "bernd@eressea.de", "de") u = unit.create(f, r, 1) u:add_item("money", 10) - turn = get_turn() end local function file_exists(name) @@ -31,9 +31,6 @@ function test_process_turn() assert_equal(0, write_reports()) assert_equal(0, eressea.write_game("test.dat")) assert_file("data/test.dat") - assert_file("reports/" .. get_turn() .. "-ii.nr", false) - assert_file("reports/" .. get_turn() .. "-ii.cr", false) - assert_file("reports/" .. get_turn() .. "-ii.txt", false) assert_file("reports/" .. get_turn() .. "-777.nr") assert_file("reports/" .. get_turn() .. "-777.cr") assert_file("reports/" .. get_turn() .. "-777.txt") diff --git a/scripts/tests/spells.lua b/scripts/tests/spells.lua index e3c0a3021..de56472c3 100644 --- a/scripts/tests/spells.lua +++ b/scripts/tests/spells.lua @@ -81,3 +81,53 @@ function test_create_dreameye() assert_equal(amax - 5, u.aura_max) end +function test_appeasement_can_move() + local u1, u2, r1, r2, uno + r1 = region.create(0, 0, 'plain') + r2 = region.create(1, 0, 'plain') + u2 = unit.create(faction.create('human'), r1, 1) + u2.race = 'elf' + u2.name = 'Angsthase' + u2.magic = 'gwyrrd' + u2:set_skill('magic', 5) + u2.aura = 10 + u2:add_spell('appeasement') + u2:add_order('NACH O') + u2:add_order('KAMPFZAUBER STUFE 1 Friedenslied') + uno = u2.id + u1 = unit.create(faction.create('human'), r1, 1) + u1:set_skill('polearm', 5) + u1:add_order('ATTACKIERE ' .. itoa36(uno)) + process_orders() + u2 = get_unit(uno) + assert_not_nil(u2) + assert_equal(r2, u2.region) + assert_equal(5, u2.status) +end + +function test_appeasement_break_guard() + local u1, u2, r1, r2, uno + r1 = region.create(0, 0, 'plain') + r2 = region.create(1, 0, 'plain') + u2 = unit.create(faction.create('human'), r1, 1) + u2.race = 'elf' + u2.name = 'Angsthase' + u2.magic = 'gwyrrd' + u2.guard = true + u2.status = 1 + u2:set_skill('magic', 5) + u2.aura = 10 + u2:add_spell('appeasement') + u2:add_order('BEWACHE') + u2:add_order('KAMPFZAUBER STUFE 1 Friedenslied') + uno = u2.id + u1 = unit.create(faction.create('human'), r1, 1) + u1:set_skill('polearm', 5) + u1:add_order('ATTACKIERE ' .. itoa36(uno)) + process_orders() + u2 = get_unit(uno) + assert_not_nil(u2) + assert_equal(r1, u2.region) + assert_equal(5, u2.status) + assert_equal(false, u2.guard) +end diff --git a/share/magic b/share/magic new file mode 100644 index 000000000..5647dd5a9 --- /dev/null +++ b/share/magic @@ -0,0 +1,3 @@ +4 lelong 0x00000002 +>0 leshort x eressea data version %d + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e5ae8de7a..8a17a45e9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -5,9 +5,8 @@ include_directories (${CMAKE_CURRENT_SOURCE_DIR}) include_directories (${CJSON_INCLUDE_DIR}) include_directories (${CLIBS_INCLUDE_DIR}) include_directories (${STORAGE_INCLUDE_DIR}) -include_directories (${LUA_INCLUDE_DIR}) include_directories (${TOLUA_INCLUDE_DIR}) -include_directories (${BSON_INCLUDE_DIR}) +include_directories (${LUA_INCLUDE_DIR}) include_directories (${INIPARSER_INCLUDE_DIR}) IF(DEFINED ERESSEA_VERSION) @@ -26,9 +25,9 @@ ENDIF() IF (CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang") # SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wconversion -Wno-sign-conversion") SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wsign-compare -Wall -Werror -Wno-unknown-pragmas -Wstrict-prototypes -Wpointer-arith -Wno-char-subscripts -Wno-long-long") - SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c89") +# SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c89") ELSEIF(MSVC) - SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Wall /WX /MP") + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W4 /WX /MP /Za /D_CRT_SECURE_NO_WARNINGS /D_USE_MATH_DEFINES") set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} /NODEFAULTLIB:libc.lib /NODEFAULTLIB:libcmt.lib /NODEFAULTLIB:libcd.lib /NODEFAULTLIB:libcmtd.lib /NODEFAULTLIB:msvcrt.lib") set(CMAKE_EXE_LINKER_FLAGS_RELEASE @@ -100,6 +99,7 @@ set (ERESSEA_SRC reports.c teleport.c guard.c + jsonconf.c prefix.c donations.c eressea.c @@ -109,6 +109,7 @@ set (ERESSEA_SRC json.c creport.c report.c + steal.c economy.c give.c items.c @@ -127,6 +128,7 @@ set (ERESSEA_SRC travelthru.c monsters.c wormhole.c + xmlreader.c ${SPELLS_SRC} ${RACES_SRC} ${ITEMS_SRC} @@ -134,12 +136,12 @@ set (ERESSEA_SRC ${TRIGGERS_SRC} ${ATTRIBUTES_SRC} ${KERNEL_SRC} + ${DB_SRC} ${UTIL_SRC} ) set(SERVER_SRC main.c - building_action.c console.c helpers.c bind_tolua.c @@ -159,13 +161,6 @@ set(SERVER_SRC bind_unit.c ) -if (SQLITE3_FOUND) -set (SERVER_SRC ${SERVER_SRC} - sqlite.c - bind_sqlite.c -) -endif (SQLITE3_FOUND) - if (CURSES_FOUND) set (SERVER_SRC ${SERVER_SRC} gmtool.c @@ -200,6 +195,7 @@ target_link_libraries(convert set(TESTS_SRC test_eressea.c tests.c + academy.test.c alchemy.test.c battle.test.c calendar.test.c @@ -210,6 +206,7 @@ set(TESTS_SRC give.test.c guard.test.c json.test.c + jsonconf.test.c keyword.test.c laws.test.c lighthouse.test.c @@ -235,6 +232,7 @@ set(TESTS_SRC volcano.test.c vortex.test.c wormhole.test.c +# xmlreader.test.c spells/flyingship.test.c spells/magicresistance.test.c triggers/shock.test.c @@ -265,9 +263,36 @@ add_test(server test_eressea) install(TARGETS eressea DESTINATION "bin") +if (HAVE_LIBBSD) + add_definitions(-DHAVE_LIBBSD) +endif (HAVE_LIBBSD) + +if (HAVE_STRLCAT) + add_definitions(-DHAVE_BSDSTRING) +endif (HAVE_STRLCAT) + +if (HAVE_STRDUP) + add_definitions(-DHAVE_STRDUP) +endif(HAVE_STRDUP) + +if (HAVE_LIBBSD) +target_link_libraries(test_eressea bsd) +target_link_libraries(eressea bsd) +target_link_libraries(convert bsd) +endif (HAVE_LIBBSD) + if (SQLITE3_FOUND) +include_directories (${SQLITE3_INCLUDE_DIR}) target_link_libraries(eressea ${SQLITE3_LIBRARIES}) +target_link_libraries(convert ${SQLITE3_LIBRARIES}) +target_link_libraries(test_eressea ${SQLITE3_LIBRARIES}) add_definitions(-DUSE_SQLITE) +elseif (DB_FOUND) +include_directories (${DB_INCLUDE_DIR}) +target_link_libraries(convert ${DB_LIBRARIES}) +target_link_libraries(eressea ${DB_LIBRARIES}) +target_link_libraries(test_eressea ${DB_LIBRARIES}) +add_definitions(-DUSE_DB) endif(SQLITE3_FOUND) if (CURSES_FOUND) @@ -281,5 +306,4 @@ include_directories (${LIBXML2_INCLUDE_DIR}) target_link_libraries(eressea ${LIBXML2_LIBRARIES}) target_link_libraries(convert ${LIBXML2_LIBRARIES}) target_link_libraries(test_eressea ${LIBXML2_LIBRARIES}) -add_definitions(-DUSE_LIBXML2) endif (LIBXML2_FOUND) diff --git a/src/academy.c b/src/academy.c index 245c89207..5df13efa4 100644 --- a/src/academy.c +++ b/src/academy.c @@ -36,8 +36,8 @@ void academy_teaching_bonus(struct unit *u, skill_t sk, int students) { bool academy_can_teach(unit *teacher, unit *student, skill_t sk) { const struct building_type *btype = bt_find("academy"); if (active_building(teacher, btype) && active_building(student, btype)) { - int j = study_cost(student, sk); - j = MAX(50, j * 2); + int j = study_cost(student, sk) * 2; + if (j < 50) j = 50; /* kann Einheit das zahlen? */ return get_pooled(student, get_resourcetype(R_SILVER), GET_DEFAULT, j) >= j; /* sonst nehmen sie nicht am Unterricht teil */ diff --git a/src/academy.test.c b/src/academy.test.c new file mode 100644 index 000000000..6e971ee60 --- /dev/null +++ b/src/academy.test.c @@ -0,0 +1,56 @@ +#include + +#include "academy.h" +#include "skill.h" + +#include +#include +#include +#include +#include +#include + +#include +#include "tests.h" + +static void test_academy(CuTest * tc) +{ + faction *f; + unit *u, *u2; + region *r; + building *b; + const item_type *it_silver; + + test_setup(); + config_set_int("skills.cost.alchemy", 100); + r = test_create_region(0, 0, NULL); + f = test_create_faction(NULL); + u = test_create_unit(f, r); + b = test_create_building(r, test_create_buildingtype("academy")); + u2 = test_create_unit(f, r); + it_silver = test_create_silver(); + + CuAssert(tc, "teacher must be in academy", !academy_can_teach(u, u2, SK_CROSSBOW)); + u_set_building(u, b); + CuAssert(tc, "student must be in academy", !academy_can_teach(u, u2, SK_CROSSBOW)); + u_set_building(u2, b); + CuAssert(tc, "student must have 50 silver", !academy_can_teach(u, u2, SK_CROSSBOW)); + i_change(&u2->items, it_silver, 50); + CuAssert(tc, "building must be maintained", !academy_can_teach(u, u2, SK_CROSSBOW)); + b->flags |= BLD_MAINTAINED; + CuAssert(tc, "building must have capacity", !academy_can_teach(u, u2, SK_CROSSBOW)); + b->size = 2; + CuAssertTrue(tc, academy_can_teach(u, u2, SK_CROSSBOW)); + + CuAssert(tc, "student must pay skillcost", !academy_can_teach(u, u2, SK_ALCHEMY)); + i_change(&u2->items, it_silver, 150); + CuAssertTrue(tc, academy_can_teach(u, u2, SK_ALCHEMY)); + test_teardown(); +} + +CuSuite *get_academy_suite(void) +{ + CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_academy); + return suite; +} diff --git a/src/alchemy.c b/src/alchemy.c index aff3485ef..75212e34a 100644 --- a/src/alchemy.c +++ b/src/alchemy.c @@ -37,6 +37,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include #include #include @@ -47,14 +48,49 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include -/* ------------------------------------------------------------- */ +typedef struct potion_type { + struct potion_type *next; + const struct item_type *itype; + int level; +} potion_type; -void herbsearch(unit * u, int max) +static potion_type *potiontypes; + +static void pt_register(potion_type * ptype) +{ + ptype->next = potiontypes; + potiontypes = ptype; +} + +void new_potiontype(item_type * itype, int level) +{ + potion_type *ptype; + + ptype = (potion_type *)calloc(sizeof(potion_type), 1); + itype->flags |= ITF_POTION; + ptype->itype = itype; + ptype->level = level; + pt_register(ptype); +} + +int potion_level(const item_type *itype) +{ + potion_type *ptype; + for (ptype = potiontypes; ptype; ptype = ptype->next) { + if (ptype->itype == itype) { + return ptype->level; + } + } + return 0; +} + +void herbsearch(unit * u, int max_take) { region * r = u->region; int herbsfound; const item_type *whichherb; int effsk = effskill(u, SK_HERBALISM, 0); + int herbs = rherbs(r); if (effsk == 0) { cmistake(u, u->thisorder, 59, MSG_PRODUCE); @@ -72,14 +108,14 @@ void herbsearch(unit * u, int max) return; } - if (max) - max = MIN(max, rherbs(r)); - else - max = rherbs(r); + if (max_take < herbs) { + herbs = max_take; + } herbsfound = ntimespprob(effsk * u->number, (double)rherbs(r) / 100.0F, -0.01F); - herbsfound = MIN(herbsfound, max); - rsetherbs(r, (short) (rherbs(r) - herbsfound)); + + if (herbsfound > herbs) herbsfound = herbs; + rsetherbs(r, rherbs(r) - herbsfound); if (herbsfound) { produceexp(u, SK_HERBALISM, u->number); @@ -93,33 +129,37 @@ void herbsearch(unit * u, int max) } } -static int begin_potion(unit * u, const potion_type * ptype, struct order *ord) +static int begin_potion(unit * u, const item_type * itype, struct order *ord) { - bool rule_multipotion; - assert(ptype != NULL); + static int config; + static bool rule_multipotion; + + assert(itype); + if (config_changed(&config)) { + /* should we allow multiple different potions to be used the same turn? */ + rule_multipotion = config_get_int("rules.magic.multipotion", 0) != 0; + } - /* should we allow multiple different potions to be used the same turn? */ - rule_multipotion = config_get_int("rules.magic.multipotion", 0) != 0; if (!rule_multipotion) { - const potion_type *use = ugetpotionuse(u); - if (use != NULL && use != ptype) { + const item_type *use = ugetpotionuse(u); + if (use != NULL && use != itype) { ADDMSG(&u->faction->msgs, msg_message("errusingpotion", "unit using command", - u, use->itype->rtype, ord)); + u, use->rtype, ord)); return ECUSTOM; } } return 0; } -static void end_potion(unit * u, const potion_type * ptype, int amount) +static void end_potion(unit * u, const item_type * itype, int amount) { - use_pooled(u, ptype->itype->rtype, GET_SLACK | GET_RESERVE | GET_POOLED_SLACK, + use_pooled(u, itype->rtype, GET_SLACK | GET_RESERVE | GET_POOLED_SLACK, amount); - usetpotionuse(u, ptype); + usetpotionuse(u, itype); ADDMSG(&u->faction->msgs, msg_message("usepotion", - "unit potion", u, ptype->itype->rtype)); + "unit potion", u, itype->rtype)); } static int potion_water_of_life(unit * u, region *r, int amount) { @@ -155,8 +195,26 @@ static int potion_water_of_life(unit * u, region *r, int amount) { return amount; } +void show_potions(faction *f, int sklevel) +{ + const potion_type *ptype; + for (ptype = potiontypes; ptype; ptype = ptype->next) { + if (ptype->level > 0 && sklevel == ptype->level * 2) { + attrib *a = a_find(f->attribs, &at_showitem); + while (a && a->type == &at_showitem && a->data.v != ptype) + a = a->next; + if (a == NULL || a->type != &at_showitem) { + a = a_add(&f->attribs, a_new(&at_showitem)); + a->data.v = (void *)ptype->itype; + } + } + } +} + static int potion_healing(unit * u, int amount) { - u->hp = MIN(unit_max_hp(u) * u->number, u->hp + 400 * amount); + int maxhp = unit_max_hp(u) * u->number; + u->hp = u->hp + 400 * amount; + if (u->hp > maxhp) u->hp = maxhp; return amount; } @@ -170,62 +228,51 @@ static int potion_luck(unit *u, region *r, attrib_type *atype, int amount) { return amount; } -static int potion_truth(unit *u) { - UNUSED_ARG(u); - /* TODO: this potion does nothing! */ - return 1; -} - static int potion_power(unit *u, int amount) { - int use = u->number / 10; - if (use < amount) { - if (u->number % 10 > 0) ++use; - amount = use; + int hp = 10 * amount; + + if (hp > u->number) { + hp = u->number; + amount = (hp + 9) % 10; } - /* Verf�nffacht die HP von max. 10 Personen in der Einheit */ - u->hp += MIN(u->number, 10 * amount) * unit_max_hp(u) * 4; + u->hp += hp * unit_max_hp(u) * 4; return amount; } -static int do_potion(unit * u, region *r, const potion_type * ptype, int amount) +static int do_potion(unit * u, region *r, const item_type * itype, int amount) { - if (ptype == oldpotiontype[P_LIFE]) { + if (itype == oldpotiontype[P_LIFE]) { return potion_water_of_life(u, r, amount); } - else if (ptype == oldpotiontype[P_HEILWASSER]) { + else if (itype == oldpotiontype[P_HEILWASSER]) { return potion_healing(u, amount); } - else if (ptype == oldpotiontype[P_PEOPLE]) { + else if (itype == oldpotiontype[P_PEOPLE]) { return potion_luck(u, r, &at_peasantluck, amount); } - else if (ptype == oldpotiontype[P_HORSE]) { + else if (itype == oldpotiontype[P_HORSE]) { return potion_luck(u, r, &at_horseluck, amount); } - else if (ptype == oldpotiontype[P_WAHRHEIT]) { - return potion_truth(u); - } - else if (ptype == oldpotiontype[P_MACHT]) { + else if (itype == oldpotiontype[P_MACHT]) { return potion_power(u, amount); } else { - change_effect(u, ptype, 10 * amount); + change_effect(u, itype, 10 * amount); } return amount; } int use_potion(unit * u, const item_type * itype, int amount, struct order *ord) { - const potion_type *ptype = resource2potion(itype->rtype); - - if (oldpotiontype[P_HEAL] && ptype == oldpotiontype[P_HEAL]) { + if (oldpotiontype[P_HEAL] && itype == oldpotiontype[P_HEAL]) { return EUNUSABLE; } else { - int result = begin_potion(u, ptype, ord); + int result = begin_potion(u, itype, ord); if (result) return result; - amount = do_potion(u, u->region, ptype, amount); - end_potion(u, ptype, amount); + amount = do_potion(u, u->region, itype, amount); + end_potion(u, itype, amount); } return 0; } @@ -233,7 +280,7 @@ int use_potion(unit * u, const item_type * itype, int amount, struct order *ord) typedef struct potiondelay { unit *u; region *r; - const potion_type *ptype; + const item_type *itype; int amount; } potiondelay; @@ -250,7 +297,7 @@ static int age_potiondelay(attrib * a, void *owner) { potiondelay *pd = (potiondelay *)a->data.v; UNUSED_ARG(owner); - pd->amount = do_potion(pd->u, pd->r, pd->ptype, pd->amount); + pd->amount = do_potion(pd->u, pd->r, pd->itype, pd->amount); return AT_AGE_REMOVE; } @@ -261,13 +308,13 @@ attrib_type at_potiondelay = { age_potiondelay, 0, 0 }; -static attrib *make_potiondelay(unit * u, const potion_type * ptype, int amount) +static attrib *make_potiondelay(unit * u, const item_type * itype, int amount) { attrib *a = a_new(&at_potiondelay); potiondelay *pd = (potiondelay *)a->data.v; pd->u = u; pd->r = u->region; - pd->ptype = ptype; + pd->itype = itype; pd->amount = amount; return a; } @@ -276,14 +323,13 @@ int use_potion_delayed(unit * u, const item_type * itype, int amount, struct order *ord) { - const potion_type *ptype = resource2potion(itype->rtype); - int result = begin_potion(u, ptype, ord); + int result = begin_potion(u, itype, ord); if (result) return result; - a_add(&u->attribs, make_potiondelay(u, ptype, amount)); + a_add(&u->attribs, make_potiondelay(u, itype, amount)); - end_potion(u, ptype, amount); + end_potion(u, itype, amount); return 0; } @@ -306,7 +352,7 @@ a_writeeffect(const attrib * a, const void *owner, struct storage *store) { effect_data *edata = (effect_data *)a->data.v; UNUSED_ARG(owner); - WRITE_TOK(store, resourcename(edata->type->itype->rtype, 0)); + WRITE_TOK(store, resourcename(edata->type->rtype, 0)); WRITE_INT(store, edata->value); } @@ -323,14 +369,16 @@ static int a_readeffect(attrib * a, void *owner, struct gamedata *data) rtype = rt_find(zText); READ_INT(store, &power); - if (rtype == NULL || rtype->ptype == NULL || power <= 0) { + if (rtype == NULL || rtype->itype == NULL || power <= 0) { return AT_READ_FAIL; } - if (rtype->ptype==oldpotiontype[P_HEAL]) { - /* healing potions used to have long-term effects */ - return AT_READ_FAIL; + if (data->version < NOLANDITEM_VERSION) { + if (rtype->itype == oldpotiontype[P_HEAL]) { + /* healing potions used to have long-term effects */ + return AT_READ_FAIL; + } } - edata->type = rtype->ptype; + edata->type = rtype->itype; edata->value = power; return AT_READ_OK; } @@ -344,7 +392,7 @@ attrib_type at_effect = { a_readeffect, }; -int get_effect(const unit * u, const potion_type * effect) +int get_effect(const unit * u, const item_type * effect) { const attrib *a; for (a = a_find(u->attribs, &at_effect); a != NULL && a->type == &at_effect; @@ -356,7 +404,7 @@ int get_effect(const unit * u, const potion_type * effect) return 0; } -int change_effect(unit * u, const potion_type * effect, int delta) +int change_effect(unit * u, const item_type * effect, int delta) { if (delta != 0) { attrib *a = a_find(u->attribs, &at_effect); @@ -386,3 +434,17 @@ int change_effect(unit * u, const potion_type * effect, int delta) log_error("change effect with delta==0 for unit %s\n", itoa36(u->no)); return 0; } + +bool display_potions(struct unit *u) +{ + int skill = effskill(u, SK_ALCHEMY, 0); + int c = 0; + const potion_type *ptype; + for (ptype = potiontypes; ptype != NULL; ptype = ptype->next) { + if (ptype->level * 2 <= skill) { + show_item(u, ptype->itype); + ++c; + } + } + return (c > 0); +} diff --git a/src/alchemy.h b/src/alchemy.h index 6dec4120b..d183cacd0 100644 --- a/src/alchemy.h +++ b/src/alchemy.h @@ -19,6 +19,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #ifndef H_KRNL_ALCHEMY_H #define H_KRNL_ALCHEMY_H +#include + #ifdef __cplusplus extern "C" { #endif @@ -26,9 +28,12 @@ extern "C" { struct potion_type; struct unit; struct region; + struct faction; struct item_type; struct order; + extern struct attrib_type at_effect; + enum { /* Stufe 1 */ P_FAST, @@ -41,11 +46,7 @@ extern "C" { /* Stufe 3 */ P_WISE, /* 6 */ P_FOOL, -#ifdef INSECT_POTION - P_WARMTH, -#else P_STEEL, -#endif P_HORSE, P_BERSERK, /* 10 */ /* Stufe 4 */ @@ -56,22 +57,24 @@ extern "C" { MAX_POTIONS }; + void new_potiontype(struct item_type * itype, int level); + int potion_level(const struct item_type *itype); + void show_potions(struct faction *f, int sklevel); + void herbsearch(struct unit *u, int max); - extern int use_potion(struct unit *u, const struct item_type *itype, + int use_potion(struct unit *u, const struct item_type *itype, int amount, struct order *); - extern int use_potion_delayed(struct unit *u, const struct item_type *itype, + int use_potion_delayed(struct unit *u, const struct item_type *itype, int amount, struct order *); - extern void init_potions(void); - - extern int get_effect(const struct unit *u, const struct potion_type *effect); - extern int change_effect(struct unit *u, const struct potion_type *effect, + int get_effect(const struct unit *u, const struct item_type *effect); + int change_effect(struct unit *u, const struct item_type *effect, int value); - extern struct attrib_type at_effect; + bool display_potions(struct unit *u); - /* rausnehmen, sobald man attribute splitten kann: */ + /* TODO: rausnehmen, sobald man attribute splitten kann: */ typedef struct effect_data { - const struct potion_type *type; + const struct item_type *type; int value; } effect_data; diff --git a/src/alchemy.test.c b/src/alchemy.test.c index c281a1c98..7510933fe 100644 --- a/src/alchemy.test.c +++ b/src/alchemy.test.c @@ -26,13 +26,14 @@ static void test_herbsearch(CuTest * tc) const item_type *itype; test_setup(); - r = test_create_region(0, 0, 0); + test_inject_messagetypes(); + r = test_create_region(0, 0, NULL); rc = rc_get_or_create("dragon"); rc->flags |= RCF_UNARMEDGUARD; u2 = test_create_unit(test_create_faction(rc), r); setguard(u2, true); - f = test_create_faction(0); + f = test_create_faction(NULL); u = test_create_unit(f, r); itype = test_create_itemtype("rosemary"); @@ -78,7 +79,7 @@ static void test_herbsearch(CuTest * tc) CuAssertPtrEquals(tc, 0, test_find_messagetype(f->msgs, "error59")); test_clear_messages(f); - test_cleanup(); + test_teardown(); } CuSuite *get_alchemy_suite(void) diff --git a/src/attributes/CMakeLists.txt b/src/attributes/CMakeLists.txt index 8be9dc7ff..fb077cfe9 100644 --- a/src/attributes/CMakeLists.txt +++ b/src/attributes/CMakeLists.txt @@ -7,7 +7,6 @@ otherfaction.test.c SET(_FILES attributes.c -fleechance.c follow.c hate.c iceberg.c diff --git a/src/attributes/attributes.c b/src/attributes/attributes.c index 95d4f41fc..a5911200c 100644 --- a/src/attributes/attributes.c +++ b/src/attributes/attributes.c @@ -25,7 +25,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* attributes includes */ #include "follow.h" -#include "fleechance.h" #include "hate.h" #include "iceberg.h" #include "key.h" @@ -56,6 +55,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include #include #include diff --git a/src/attributes/dict.c b/src/attributes/dict.c index f95555734..83a53dbeb 100644 --- a/src/attributes/dict.c +++ b/src/attributes/dict.c @@ -34,6 +34,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include #include @@ -69,7 +70,7 @@ static int dict_read(attrib * a, void *owner, gamedata *data) int n; READ_STR(store, name, sizeof(name)); - dd->name = strdup(name); + dd->name = str_strdup(name); READ_INT(store, &n); dd->type = (dict_type)n; if (dd->type == TINTEGER) { @@ -135,7 +136,13 @@ static void dict_upgrade(attrib **alist, attrib *abegin) { assert(!"invalid input"); } if (i == 4) { - keys = realloc(keys, sizeof(int) * (n + i + 1)); + int *k; + k = realloc(keys, sizeof(int) * (n + i + 1)); + if (!k) { + free(keys); + abort(); + } + keys = k; memcpy(keys + n + 1, val, sizeof(val)); n += i; i = 0; @@ -164,7 +171,7 @@ attrib_type at_dict = { void dict_set(attrib * a, const char * name, int value) { dict_data *dd = (dict_data *)a->data.v; - dd->name = strdup(name); + dd->name = str_strdup(name); dd->type = TINTEGER; dd->data.i = value; } diff --git a/src/attributes/fleechance.c b/src/attributes/fleechance.c deleted file mode 100644 index b8012fba5..000000000 --- a/src/attributes/fleechance.c +++ /dev/null @@ -1,40 +0,0 @@ -/* -Copyright (c) 1998-2015, Enno Rehling -Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include "fleechance.h" - -#include - -#include - -attrib_type at_fleechance = { - "fleechance", - NULL, - NULL, - NULL, - NULL, - NULL, -}; - -attrib *make_fleechance(float fleechance) -{ - attrib *a = a_new(&at_fleechance); - a->data.flt = fleechance; - return a; -} diff --git a/src/attributes/fleechance.h b/src/attributes/fleechance.h deleted file mode 100644 index d5817b8b7..000000000 --- a/src/attributes/fleechance.h +++ /dev/null @@ -1,32 +0,0 @@ -/* -Copyright (c) 1998-2015, Enno Rehling -Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ATTRIBUTE_FLEECHANCE -#define H_ATTRIBUTE_FLEECHANCE -#ifdef __cplusplus -extern "C" { -#endif - - extern struct attrib_type at_fleechance; - - struct attrib *make_fleechance(float fleechance); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/src/attributes/hate.c b/src/attributes/hate.c index 7cba12514..e6751bdfb 100644 --- a/src/attributes/hate.c +++ b/src/attributes/hate.c @@ -24,6 +24,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include +#include #include #include diff --git a/src/attributes/key.c b/src/attributes/key.c index 00f81a80e..61bbb4599 100644 --- a/src/attributes/key.c +++ b/src/attributes/key.c @@ -123,8 +123,14 @@ static int a_readkeys(attrib * a, void *owner, gamedata *data) { if (e != n) { int sz = keys_size(n); if (e > sz) { + int *k; sz = keys_size(e); - keys = realloc(keys, sizeof(int)*(2 * sz + 1)); + k = realloc(keys, sizeof(int)*(2 * sz + 1)); + if (!k) { + free(keys); + abort(); + } + keys = k; keys[0] = e; } } diff --git a/src/attributes/moved.c b/src/attributes/moved.c index c66a5489c..e34b9c5e8 100644 --- a/src/attributes/moved.c +++ b/src/attributes/moved.c @@ -22,6 +22,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include +#include #include diff --git a/src/attributes/movement.c b/src/attributes/movement.c index 4d79039ef..1b5ba3f94 100644 --- a/src/attributes/movement.c +++ b/src/attributes/movement.c @@ -22,6 +22,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include +#include #include diff --git a/src/attributes/otherfaction.test.c b/src/attributes/otherfaction.test.c index a28d9f470..8417ed3e3 100644 --- a/src/attributes/otherfaction.test.c +++ b/src/attributes/otherfaction.test.c @@ -30,7 +30,7 @@ static void test_rules(CuTest *tc) { CuAssertIntEquals(tc, false, rule_stealth_anon()); config_set("stealth.faction.anon", "1"); CuAssertIntEquals(tc, true, rule_stealth_anon()); - test_cleanup(); + test_teardown(); } static void test_otherfaction(CuTest *tc) { @@ -38,14 +38,14 @@ static void test_otherfaction(CuTest *tc) { faction *f; test_setup(); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); - f = test_create_faction(0); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); + f = test_create_faction(NULL); config_set("stealth.faction.other", "1"); CuAssertIntEquals(tc, true, rule_stealth_other()); CuAssertPtrEquals(tc, u->faction, visible_faction(f, u)); a_add(&u->attribs, make_otherfaction(f)); CuAssertPtrEquals(tc, f, visible_faction(f, u)); - test_cleanup(); + test_teardown(); } CuSuite *get_otherfaction_suite(void) diff --git a/src/attributes/racename.c b/src/attributes/racename.c index c45fa3815..c46fb0c4b 100644 --- a/src/attributes/racename.c +++ b/src/attributes/racename.c @@ -21,6 +21,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "racename.h" #include +#include /* libc includes */ #include @@ -43,7 +44,7 @@ void set_racename(attrib ** palist, const char *name) attrib *a = a_find(*palist, &at_racename); if (!a && name) { a = a_add(palist, a_new(&at_racename)); - a->data.v = strdup(name); + a->data.v = str_strdup(name); } else if (a && !name) { a_remove(palist, a); @@ -51,7 +52,7 @@ void set_racename(attrib ** palist, const char *name) else if (a) { if (strcmp(a->data.v, name) != 0) { free(a->data.v); - a->data.v = strdup(name); + a->data.v = str_strdup(name); } } } diff --git a/src/attributes/raceprefix.c b/src/attributes/raceprefix.c index a87edfb80..233d17e40 100644 --- a/src/attributes/raceprefix.c +++ b/src/attributes/raceprefix.c @@ -21,6 +21,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "raceprefix.h" #include +#include #include #include @@ -41,7 +42,7 @@ void set_prefix(attrib ** ap, const char *str) free(a->data.v); } assert(a->type == &at_raceprefix); - a->data.v = strdup(str); + a->data.v = str_strdup(str); } const char *get_prefix(attrib * a) @@ -53,7 +54,7 @@ const char *get_prefix(attrib * a) str = (char *)a->data.v; /* conversion of old prefixes */ if (strncmp(str, "prefix_", 7) == 0) { - ((attrib *)a)->data.v = strdup(str + 7); + ((attrib *)a)->data.v = str_strdup(str + 7); free(str); str = (char *)a->data.v; } diff --git a/src/attributes/stealth.test.c b/src/attributes/stealth.test.c index 818633d06..36c020e7d 100644 --- a/src/attributes/stealth.test.c +++ b/src/attributes/stealth.test.c @@ -14,8 +14,8 @@ static void test_stealth(CuTest *tc) { unit *u; - test_cleanup(); - u = test_create_unit(test_create_faction(test_create_race("human")), test_create_region(0, 0, 0)); + test_setup(); + u = test_create_unit(test_create_faction(test_create_race("human")), test_create_region(0, 0, NULL)); set_level(u, SK_STEALTH, 2); CuAssertIntEquals(tc, -1, u_geteffstealth(u)); CuAssertIntEquals(tc, 2, eff_stealth(u, u->region)); @@ -28,7 +28,7 @@ static void test_stealth(CuTest *tc) { u_seteffstealth(u, -1); CuAssertIntEquals(tc, -1, u_geteffstealth(u)); CuAssertIntEquals(tc, 2, eff_stealth(u, u->region)); - test_cleanup(); + test_teardown(); } CuSuite *get_stealth_suite(void) diff --git a/src/battle.c b/src/battle.c index a63caa291..b7482e48a 100644 --- a/src/battle.c +++ b/src/battle.c @@ -55,7 +55,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* attributes includes */ #include -#include #include #include #include @@ -64,15 +63,17 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include -#include #include #include #include +#include #include -#include +#include #include #include +#include + /* libc includes */ #include #include @@ -141,11 +142,14 @@ static int rule_tactics_formula; static int rule_nat_armor; static int rule_cavalry_mode; static int rule_vampire; +static const item_type *it_mistletoe; /** initialize rules from configuration. */ static void init_rules(void) { + it_mistletoe = it_find("mistletoe"); + rule_nat_armor = config_get_int("rules.combat.nat_armor", 0); rule_tactics_formula = config_get_int("rules.tactics.formula", 0); rule_goblin_bonus = config_get_int("rules.combat.goblinbonus", 10); @@ -182,14 +186,14 @@ static int army_index(side * s) return s->index; } -static char *sidename(side * s) +const char *sidename(const side * s) { #define SIDENAMEBUFLEN 256 static int bufno; /* STATIC_XCALL: used across calls */ static char sidename_buf[4][SIDENAMEBUFLEN]; /* STATIC_RESULT: used for return, not across calls */ bufno = bufno % 4; - strlcpy(sidename_buf[bufno], factionname(s->stealthfaction ? s->stealthfaction : s->faction), SIDENAMEBUFLEN); + str_strlcpy(sidename_buf[bufno], factionname(s->stealthfaction ? s->stealthfaction : s->faction), SIDENAMEBUFLEN); return sidename_buf[bufno++]; } @@ -199,11 +203,11 @@ static const char *sideabkz(side * s, bool truename) const faction *f = (s->stealthfaction && !truename) ? s->stealthfaction : s->faction; - strlcpy(sideabkz_buf, itoa36(f->no), sizeof(sideabkz_buf)); + str_strlcpy(sideabkz_buf, itoa36(f->no), sizeof(sideabkz_buf)); return sideabkz_buf; } -static void message_faction(battle * b, faction * f, struct message *m) +void battle_message_faction(battle * b, faction * f, struct message *m) { region *r = b->region; @@ -224,14 +228,14 @@ void message_all(battle * b, message * m) for (bf = b->factions; bf; bf = bf->next) { assert(bf->faction); - message_faction(b, bf->faction, m); + battle_message_faction(b, bf->faction, m); } } static void fbattlerecord(battle * b, faction * f, const char *s) { message *m = msg_message("battle_msg", "string", s); - message_faction(b, f, m); + battle_message_faction(b, f, m); msg_release(m); } @@ -639,8 +643,6 @@ weapon_skill(const weapon_type * wtype, const unit * u, bool attacking) if (!i_canuse(u, wtype->itype)) return -1; skill = effskill(u, wtype->skill, 0); - if (skill < wtype->minskill) - skill = 0; if (skill > 0) { if (attacking) { skill += u_race(u)->at_bonus; @@ -679,7 +681,7 @@ static int CavalryBonus(const unit * u, troop enemy, int type) /* only half against trolls */ if (skl > 0) { if (type == BONUS_SKILL) { - int dmg = MIN(skl, 8); + int dmg = (skl < 8) ? skl : 8; if (u_race(enemy.fighter->unit) == get_race(RC_TROLL)) { dmg = dmg / 4; } @@ -690,7 +692,8 @@ static int CavalryBonus(const unit * u, troop enemy, int type) } else { skl = skl / 2; - return MIN(skl, 4); + if (skl > 4) skl = 4; + return skl; } } } @@ -887,7 +890,7 @@ static void rmtroop(troop dt) { fighter *df = dt.fighter; - /* troop ist immer eine einzele Person */ + /* troop ist immer eine einzelne Person */ rmfighter(df, 1); assert(dt.index >= 0 && dt.index < df->unit->number); @@ -943,8 +946,8 @@ void drain_exp(struct unit *u, int n) skill_t sk = (skill_t)(rng_int() % MAXSKILLS); skill_t ssk; + /* TODO (enno): we can use u->skill_size to find a random skill */ ssk = sk; - while (get_level(u, sk) == 0) { sk++; if (sk == MAXSKILLS) @@ -984,8 +987,10 @@ static void vampirism(troop at, int damage) ++gain; if (gain > 0) { int maxhp = unit_max_hp(at.fighter->unit); - at.fighter->person[at.index].hp = - MIN(gain + at.fighter->person[at.index].hp, maxhp); + + gain += at.fighter->person[at.index].hp; + if (maxhp > gain) maxhp = gain; + at.fighter->person[at.index].hp = maxhp; } } } @@ -1009,7 +1014,7 @@ int natural_armor(unit * du) static int rc_specialdamage(const unit *au, const unit *du, const struct weapon_type *wtype) { const race *ar = u_race(au); - int m, modifier = 0; + int modifier = 0; if (wtype != NULL) { if (fval(u_race(du), RCF_DRAGON)) { static int cache; @@ -1022,6 +1027,7 @@ static int rc_specialdamage(const unit *au, const unit *du, const struct weapon_ } } if (wtype->modifiers != NULL) { + int m; for (m = 0; wtype->modifiers[m].value; ++m) { /* weapon damage for this weapon, possibly by race */ if (wtype->modifiers[m].flags & WMF_DAMAGE) { @@ -1141,7 +1147,7 @@ terminate(troop dt, troop at, int type, const char *damage, bool missile) const weapon_type *dwtype = NULL; const weapon_type *awtype = NULL; const weapon *weapon; - variant res = frac_make(1, 1); + variant res = frac_one; int rda, sk = 0, sd; bool magic = false; @@ -1185,6 +1191,7 @@ terminate(troop dt, troop at, int type, const char *damage, bool missile) } if (magic) { + res = frac_sub(frac_one, res); res = frac_mul(frac_make(da, 1), res); da = res.sa[0] / res.sa[1]; } @@ -1194,8 +1201,8 @@ terminate(troop dt, troop at, int type, const char *damage, bool missile) double kritchance = (sk * 3 - sd) / 200.0; int maxk = 4; - kritchance = MAX(kritchance, 0.005); - kritchance = MIN(0.9, kritchance); + kritchance = fmax(kritchance, 0.005); + kritchance = fmin(0.9, kritchance); while (maxk-- && chance(kritchance)) { da += dice_rand(damage); @@ -1294,11 +1301,11 @@ terminate(troop dt, troop at, int type, const char *damage, bool missile) } if (oldpotiontype[P_HEAL] && !fval(&df->person[dt.index], FL_HEALING_USED)) { - if (i_get(du->items, oldpotiontype[P_HEAL]->itype) > 0) { + if (i_get(du->items, oldpotiontype[P_HEAL]) > 0) { message *m = msg_message("potionsave", "unit", du); - message_faction(b, du->faction, m); + battle_message_faction(b, du->faction, m); msg_release(m); - i_change(&du->items, oldpotiontype[P_HEAL]->itype, -1); + i_change(&du->items, oldpotiontype[P_HEAL], -1); fset(&df->person[dt.index], FL_HEALING_USED); df->person[dt.index].hp = u_race(du)->hitpoints * 5; /* give the person a buffer */ return false; @@ -1641,7 +1648,6 @@ static castorder * create_castorder_combat(castorder *co, fighter *fig, const sp return co; } -#ifdef FFL_CURSED static void summon_igjarjuk(battle *b, spellrank spellranks[]) { side *s; castorder *co; @@ -1679,7 +1685,6 @@ static void summon_igjarjuk(battle *b, spellrank spellranks[]) { } } } -#endif void do_combatmagic(battle * b, combatmagic_t was) { @@ -1691,11 +1696,9 @@ void do_combatmagic(battle * b, combatmagic_t was) memset(spellranks, 0, sizeof(spellranks)); -#ifdef FFL_CURSED if (was == DO_PRECOMBATSPELL) { summon_igjarjuk(b, spellranks); } -#endif for (s = b->sides; s != b->sides + b->nsides; ++s) { fighter *fig; for (fig = s->fighters; fig; fig = fig->next) { @@ -1734,8 +1737,9 @@ void do_combatmagic(battle * b, combatmagic_t was) } level = eff_spelllevel(mage, sp, level, 1); - if (sl > 0) - level = MIN(sl, level); + if (sl > 0 && sl < level) { + level = sl; + } if (level < 0) { report_failed_spell(b, mage, sp); free_order(ord); @@ -1815,8 +1819,10 @@ static void do_combatspell(troop at) } level = eff_spelllevel(caster, sp, fi->magic, 1); - if ((sl = get_combatspelllevel(caster, 1)) > 0) - level = MIN(level, sl); + sl = get_combatspelllevel(caster, 1); + if (sl > 0 && sl < level) { + level = sl; + } if (fumble(r, caster, sp, level)) { report_failed_spell(b, caster, sp); @@ -2008,11 +2014,6 @@ void dazzle(battle * b, troop * td) { UNUSED_ARG(b); /* Nicht kumulativ ! */ -#ifdef TODO_RUNESWORD - if (td->fighter->weapon[WP_RUNESWORD].count > td->index) { - return; - } -#endif if (td->fighter->person[td->index].flags & (FL_COURAGE|FL_DAZZLED)) { return; } @@ -2284,21 +2285,6 @@ void do_attack(fighter * af) } } -void do_regenerate(fighter * af) -{ - troop ta; - unit *au = af->unit; - - ta.fighter = af; - ta.index = af->fighting; - - while (ta.index--) { - struct person *p = af->person + ta.index; - p->hp += effskill(au, SK_STAMINA, 0); - p->hp = MIN(unit_max_hp(au), p->hp); - } -} - static void add_tactics(tactics * ta, fighter * fig, int value) { if (value == 0 || value < ta->value) @@ -2345,28 +2331,22 @@ static double horse_fleeing_bonus(const unit * u) double fleechance(unit * u) { - double c = 0.20; /* Fluchtwahrscheinlichkeit in % */ - attrib *a = a_find(u->attribs, &at_fleechance); + double p = 0.20; /* Fluchtwahrscheinlichkeit in % */ /* Einheit u versucht, dem Get�mmel zu entkommen */ - c += (effskill(u, SK_STEALTH, 0) * 0.05); - c += horse_fleeing_bonus(u); + p += (effskill(u, SK_STEALTH, 0) * 0.05); + p += horse_fleeing_bonus(u); if (u_race(u) == get_race(RC_HALFLING)) { - c += 0.20; - c = MIN(c, 0.90); - } - else { - c = MIN(c, 0.75); + p += 0.20; + if (p > 0.9) { + p = 0.9; + } } - - if (a != NULL) - c += a->data.flt; - - return c; + return p; } -/** add a new army to the conflict +/** add a new army to the conflict. * beware: armies need to be added _at the beginning_ of the list because * otherwise join_allies() will get into trouble */ side *make_side(battle * b, const faction * f, const group * g, @@ -2482,7 +2462,7 @@ static void loot_items(fighter * corpse) float lootfactor = (float)dead / (float)u->number; /* only loot the dead! */ int maxloot = (int)((float)itm->number * lootfactor); if (maxloot > 0) { - int i = MIN(10, maxloot); + int i = (maxloot > 10) ? 10 : maxloot; for (; i != 0; --i) { int loot = maxloot / i; @@ -2545,7 +2525,7 @@ static void loot_items(fighter * corpse) } } -static bool seematrix(const faction * f, const side * s) +bool seematrix(const faction * f, const side * s) { if (f == s->faction) return true; @@ -2562,12 +2542,18 @@ static double PopulationDamage(void) static void battle_effects(battle * b, int dead_players) { region *r = b->region; - int dead_peasants = - MIN(rpeasants(r), (int)(dead_players * PopulationDamage())); - if (dead_peasants) { - deathcounts(r, dead_peasants + dead_players); - add_chaoscount(r, dead_peasants / 2); - rsetpeasants(r, rpeasants(r) - dead_peasants); + int rp = rpeasants(r); + + if (rp > 0) { + int dead_peasants = (int)(dead_players * PopulationDamage()); + if (dead_peasants > rp) { + dead_peasants = rp; + } + if (dead_peasants) { + deathcounts(r, dead_peasants + dead_players); + add_chaoscount(r, dead_peasants / 2); + rsetpeasants(r, rp - dead_peasants); + } } } @@ -2623,7 +2609,7 @@ static void aftermath(battle * b) struct message *m = msg_message("killsandhits", "unit hits kills", du, df->hits, df->kills); - message_faction(b, du->faction, m); + battle_message_faction(b, du->faction, m); msg_release(m); } } @@ -2654,14 +2640,14 @@ static void aftermath(battle * b) } } snumber += du->number; - if (relevant) { - flags = UFL_LONGACTION | UFL_NOTMOVING; - if (du->status == ST_FLEE) { - flags -= UFL_NOTMOVING; - } - } if (df->alive == 0) { - flags |= UFL_DEAD; + flags = UFL_DEAD; + } + else if (relevant) { + flags = UFL_LONGACTION; + if ((du->status != ST_FLEE) && (df->run.hp <= 0)) { + flags |= UFL_NOTMOVING; + } } if (flags) { fset(du, flags); @@ -2763,7 +2749,7 @@ static void aftermath(battle * b) faction *f = bf->faction; message *m = seematrix(f, s) ? seen : unseen; - message_faction(b, f, m); + battle_message_faction(b, f, m); } msg_release(seen); @@ -2787,7 +2773,7 @@ static void aftermath(battle * b) message *m = msg_message("battle_loot", "unit amount item", du, l->number, itype->rtype); - message_faction(b, du->faction, m); + battle_message_faction(b, du->faction, m); msg_release(m); i_change(&du->items, itype, l->number); } @@ -2885,54 +2871,6 @@ static void set_attacker(fighter * fig) fset(fig, FIG_ATTACKER); } -static void print_header(battle * b) -{ - bfaction *bf; - char zText[32 * MAXSIDES]; - - for (bf = b->factions; bf; bf = bf->next) { - message *m; - faction *f = bf->faction; - const char *lastf = NULL; - bool first = false; - side *s; - char *bufp = zText; - size_t size = sizeof(zText) - 1; - - for (s = b->sides; s != b->sides + b->nsides; ++s) { - fighter *df; - for (df = s->fighters; df; df = df->next) { - if (is_attacker(df)) { - if (first) { - bufp = STRLCPY(bufp, ", ", size); - } - if (lastf) { - bufp = STRLCPY(bufp, lastf, size); - first = true; - } - if (seematrix(f, s)) - lastf = sidename(s); - else - lastf = LOC(f->locale, "unknown_faction_dative"); - break; - } - } - } - if (first) { - bufp = STRLCPY(bufp, " ", size); - bufp = STRLCPY(bufp, LOC(f->locale, "and"), size); - bufp = STRLCPY(bufp, " ", size); - } - if (lastf) { - bufp = STRLCPY(bufp, lastf, size); - } - - m = msg_message("start_battle", "factions", zText); - message_faction(b, f, m); - msg_release(m); - } -} - static void print_stats(battle * b) { side *s2; @@ -2955,10 +2893,10 @@ static void print_stats(battle * b) message *msg; char buf[1024]; - message_faction(b, f, msg_separator); + battle_message_faction(b, f, msg_separator); msg = msg_message("battle_army", "index name", army_index(s), sname); - message_faction(b, f, msg); + battle_message_faction(b, f, msg); msg_release(msg); bufp = buf; @@ -3195,7 +3133,8 @@ fighter *make_fighter(battle * b, unit * u, side * s1, bool attack) /* change_effect wird in ageing gemacht */ /* Effekte von Artefakten */ - strongmen = MIN(fig->unit->number, trollbelts(u)); + strongmen = trollbelts(u); + if (strongmen > fig->unit->number) strongmen = fig->unit->number; /* Hitpoints, Attack- und Defence-Boni f�r alle Personen */ for (i = 0; i < fig->alive; i++) { @@ -3415,24 +3354,14 @@ fighter * get_fighter(battle * b, const struct unit * u) static int join_battle(battle * b, unit * u, bool attack, fighter ** cp) { side *s; - fighter *c = NULL; - - if (!attack) { - attrib *a = a_find(u->attribs, &at_fleechance); - if (a != NULL) { - if (rng_double() <= a->data.flt) { - *cp = NULL; - return false; - } - } - } + fighter *fc = NULL; for (s = b->sides; s != b->sides + b->nsides; ++s) { fighter *fig; if (s->faction == u->faction) { for (fig = s->fighters; fig; fig = fig->next) { if (fig->unit == u) { - c = fig; + fc = fig; if (attack) { set_attacker(fig); } @@ -3441,11 +3370,11 @@ static int join_battle(battle * b, unit * u, bool attack, fighter ** cp) } } } - if (!c) { + if (!fc) { *cp = make_fighter(b, u, NULL, attack); return *cp != NULL; } - *cp = c; + *cp = fc; return false; } @@ -3572,17 +3501,17 @@ static int battle_report(battle * b) for (bf = b->factions; bf; bf = bf->next) { faction *fac = bf->faction; char buf[32 * MAXSIDES]; - char *bufp = buf; - size_t size = sizeof(buf) - 1; message *m; + sbstring sbs; - message_faction(b, fac, msg_separator); + sbs_init(&sbs, buf, sizeof(buf)); + battle_message_faction(b, fac, msg_separator); if (cont) m = msg_message("lineup_battle", "turn", b->turn); else m = msg_message("after_battle", ""); - message_faction(b, fac, m); + battle_message_faction(b, fac, m); msg_release(m); komma = false; @@ -3595,24 +3524,22 @@ static int battle_report(battle * b) char buffer[32]; if (komma) { - bufp = STRLCPY(bufp, ", ", size); + sbs_strcat(&sbs, ", "); } - slprintf(buffer, sizeof(buffer), "%s %2d(%s): ", + snprintf(buffer, sizeof(buffer), "%s %2d(%s): ", loc_army, army_index(s), abbrev); - - bufp = STRLCPY(bufp, buffer, size); + sbs_strcat(&sbs, buffer); for (r = FIGHT_ROW; r != NUMROWS; ++r) { if (alive[r]) { if (l != FIGHT_ROW) { - bufp = STRLCPY(bufp, "+", size); + sbs_strcat(&sbs, "+"); } while (k--) { - bufp = STRLCPY(bufp, "0+", size); + sbs_strcat(&sbs, "0+"); } sprintf(buffer, "%d", alive[r]); - - bufp = STRLCPY(bufp, buffer, size); + sbs_strcat(&sbs, buffer); k = 0; l = r + 1; @@ -3624,7 +3551,6 @@ static int battle_report(battle * b) komma = true; } } - *bufp = 0; fbattlerecord(b, fac, buf); } return cont; @@ -3841,7 +3767,7 @@ static bool start_battle(region * r, battle ** bp) /* Ende Fehlerbehandlung Angreifer */ - init_order(ord); + init_order_depr(ord); /* attackierte Einheit ermitteln */ getunit(r, u->faction, &u2); @@ -3885,13 +3811,27 @@ static bool start_battle(region * r, battle ** bp) join_battle(b, u, true, &c1); join_battle(b, u2, false, &c2); + if (u2->attribs) { + if (it_mistletoe) { + int effect = get_effect(u2, it_mistletoe); + if (effect >= u->number) { + change_effect(u2, it_mistletoe, -u2->number); + c2->run.hp = u2->hp; + c2->run.number = u2->number; + c2->side->flee += u2->number; + setguard(u2, false); + rmfighter(c2, u2->number); + } + } + } + /* Hat die attackierte Einheit keinen Noaid-Status, * wird das Flag von der Faction genommen, andere * Einheiten greifen ein. */ if (!fval(u2, UFL_NOAID)) freset(u2->faction, FFL_NOAID); - if (c1 != NULL && c2 != NULL) { + if (c1 && c2 && c2->run.number < c2->unit->number) { /* Merken, wer Angreifer ist, f�r die R�ckzahlung der * Pr�combataura bei kurzem Kampf. */ c1->side->bf->attacker = true; @@ -3967,7 +3907,8 @@ static void battle_flee(battle * b) troop dt; int runners = 0; /* Flucht nicht bei mehr als 600 HP. Damit Wyrme t�tbar bleiben. */ - int runhp = MIN(600, (int)(0.9 + unit_max_hp(u) * hpflee(u->status))); + int runhp = (int)(0.9 + unit_max_hp(u) * hpflee(u->status)); + if (runhp > 600) runhp = 600; if (u->ship && fval(u->region->terrain, SEA_REGION)) { /* keine Flucht von Schiffen auf hoher See */ @@ -4010,7 +3951,7 @@ static void battle_flee(battle * b) if (fig->person[dt.index].flags & FL_PANICED) { ispaniced = EFFECT_PANIC_SPELL; } - if (chance(MIN(fleechance(u) + ispaniced, 0.90))) { + if (chance(fmin(fleechance(u) + ispaniced, 0.90))) { ++runners; flee(dt); } @@ -4084,7 +4025,7 @@ void do_battle(region * r) /* Bevor wir die alliierten hineinziehen, sollten wir schauen, * * Ob jemand fliehen kann. Dann er�brigt sich das ganze ja * vielleicht schon. */ - print_header(b); + report_battle_start(b); if (!fighting) { /* Niemand mehr da, Kampf kann nicht stattfinden. */ message *m = msg_message("aborted_battle", ""); diff --git a/src/battle.h b/src/battle.h index 3c86c2c8d..6494a6e27 100644 --- a/src/battle.h +++ b/src/battle.h @@ -47,7 +47,6 @@ extern "C" { #define LAST_ROW FLEE_ROW #define MAXSIDES 192 /* if there are ever more than this, we're fucked. */ - typedef struct bfaction { struct bfaction *next; struct side *sides; @@ -172,17 +171,6 @@ extern "C" { int catmsg; /* Merkt sich, ob Katapultmessage schon generiert. */ struct person { int hp; /* Trefferpunkte der Personen */ -#ifdef LOMEM - int attack : 8; /* (Magie) Attackenbonus der Personen */ - int defence : 8; /* (Magie) Paradenbonus der Personen */ - int damage : 8; /* (Magie) Schadensbonus der Personen im Nahkampf */ - int damage_rear : 8; /* (Magie) Schadensbonus der Personen im Fernkampf */ - int flags : 8; /* (Magie) Diverse Flags auf Kaempfern */ - int speed : 8; /* (Magie) Geschwindigkeitsmultiplkator. */ - int reload : 4; /* Anzahl Runden, die die Waffe x noch laden muss. - * dahinter steckt ein array[RL_MAX] wenn er min. eine hat. */ - int last_action : 4; /* In welcher Runde haben wir zuletzt etwas getan */ -#else int attack; int defence; int damage; @@ -191,7 +179,6 @@ extern "C" { int speed; int reload; int last_action; -#endif struct weapon *missile; /* missile weapon */ struct weapon *melee; /* melee weapon */ } *person; @@ -278,6 +265,9 @@ extern "C" { const struct faction * stealthfaction); int skilldiff(troop at, troop dt, int dist); void force_leave(struct region *r, struct battle *b); + bool seematrix(const struct faction * f, const struct side * s); + const char *sidename(const struct side * s); + void battle_message_faction(struct battle * b, struct faction * f, struct message *m); #ifdef __cplusplus } diff --git a/src/battle.test.c b/src/battle.test.c index 3669f25d1..d446cbebb 100644 --- a/src/battle.test.c +++ b/src/battle.test.c @@ -36,7 +36,7 @@ static void test_make_fighter(CuTest * tc) test_setup(); test_create_horse(); - r = test_create_region(0, 0, 0); + r = test_create_region(0, 0, NULL); f = test_create_faction(NULL); au = test_create_unit(f, r); enable_skill(SK_MAGIC, true); @@ -65,7 +65,7 @@ static void test_make_fighter(CuTest * tc) CuAssertIntEquals(tc, 1, af->horses); CuAssertIntEquals(tc, 0, af->elvenhorses); free_battle(b); - test_cleanup(); + test_teardown(); } static building_type * setup_castle(void) { @@ -94,7 +94,7 @@ static void test_defenders_get_building_bonus(CuTest * tc) test_setup(); btype = setup_castle(); - r = test_create_region(0, 0, 0); + r = test_create_region(0, 0, NULL); bld = test_create_building(r, btype); du = test_create_unit(test_create_faction(NULL), r); @@ -124,7 +124,7 @@ static void test_defenders_get_building_bonus(CuTest * tc) CuAssertIntEquals(tc, 0, skilldiff(dt, at, 0)); free_battle(b); - test_cleanup(); + test_teardown(); } static void test_attackers_get_no_building_bonus(CuTest * tc) @@ -138,7 +138,7 @@ static void test_attackers_get_no_building_bonus(CuTest * tc) building_type * btype; test_setup(); - r = test_create_region(0, 0, 0); + r = test_create_region(0, 0, NULL); btype = setup_castle(); btype->flags |= BTF_FORTIFICATION; bld = test_create_building(r, btype); @@ -153,7 +153,7 @@ static void test_attackers_get_no_building_bonus(CuTest * tc) CuAssertPtrEquals(tc, 0, af->building); free_battle(b); - test_cleanup(); + test_teardown(); } static void test_building_bonus_respects_size(CuTest * tc) @@ -169,7 +169,7 @@ static void test_building_bonus_respects_size(CuTest * tc) test_setup(); btype = setup_castle(); - r = test_create_region(0, 0, 0); + r = test_create_region(0, 0, NULL); btype->flags |= BTF_FORTIFICATION; bld = test_create_building(r, btype); bld->size = 10; @@ -190,7 +190,7 @@ static void test_building_bonus_respects_size(CuTest * tc) CuAssertPtrEquals(tc, bld, af->building); CuAssertPtrEquals(tc, 0, df->building); free_battle(b); - test_cleanup(); + test_teardown(); } static void test_building_defence_bonus(CuTest * tc) @@ -214,7 +214,7 @@ static void test_building_defence_bonus(CuTest * tc) CuAssertIntEquals(tc, 1, building_protection(btype, 1)); CuAssertIntEquals(tc, 2, building_protection(btype, 2)); CuAssertIntEquals(tc, 2, building_protection(btype, 3)); - test_cleanup(); + test_teardown(); } static fighter *setup_fighter(battle **bp, unit *u) { @@ -235,7 +235,7 @@ static void test_natural_armor(CuTest * tc) test_setup(); rc = test_create_race("human"); - u = test_create_unit(test_create_faction(rc), test_create_region(0, 0, 0)); + u = test_create_unit(test_create_faction(rc), test_create_region(0, 0, NULL)); set_level(u, SK_STAMINA, 2); CuAssertIntEquals(tc, 0, rc_armor_bonus(rc)); CuAssertIntEquals(tc, 0, natural_armor(u)); @@ -245,7 +245,7 @@ static void test_natural_armor(CuTest * tc) rc_set_param(rc, "armor.stamina", "2"); CuAssertIntEquals(tc, 2, rc_armor_bonus(rc)); CuAssertIntEquals(tc, 1, natural_armor(u)); - test_cleanup(); + test_teardown(); } static void test_calculate_armor(CuTest * tc) @@ -262,13 +262,13 @@ static void test_calculate_armor(CuTest * tc) variant v50p = frac_make(1, 2); test_setup(); - r = test_create_region(0, 0, 0); + r = test_create_region(0, 0, NULL); ibelt = it_get_or_create(rt_get_or_create("trollbelt")); ishield = it_get_or_create(rt_get_or_create("shield")); ashield = new_armortype(ishield, 0.0, v50p, 1, ATF_SHIELD); ichain = it_get_or_create(rt_get_or_create("chainmail")); achain = new_armortype(ichain, 0.0, v50p, 3, ATF_NONE); - wtype = new_weapontype(it_get_or_create(rt_get_or_create("sword")), 0, v50p, 0, 0, 0, 0, SK_MELEE, 1); + wtype = new_weapontype(it_get_or_create(rt_get_or_create("sword")), 0, v50p, 0, 0, 0, 0, SK_MELEE); rc = test_create_race("human"); du = test_create_unit(test_create_faction(rc), r); dt.index = 0; @@ -316,7 +316,7 @@ static void test_calculate_armor(CuTest * tc) CuAssertIntEquals_Msg(tc, "laen armor", 3, calculate_armor(dt, 0, 0, &magres)); CuAssertIntEquals_Msg(tc, "laen magres bonus", 4, magres.sa[1]); free_battle(b); - test_cleanup(); + test_teardown(); } static void test_magic_resistance(CuTest *tc) @@ -333,7 +333,7 @@ static void test_magic_resistance(CuTest *tc) variant v10p = frac_make(1, 10); test_setup(); - r = test_create_region(0, 0, 0); + r = test_create_region(0, 0, NULL); ishield = it_get_or_create(rt_get_or_create("shield")); ashield = new_armortype(ishield, 0.0, v50p, 1, ATF_SHIELD); ichain = it_get_or_create(rt_get_or_create("chainmail")); @@ -388,7 +388,7 @@ static void test_magic_resistance(CuTest *tc) CuAssert(tc, "damage reduction is never < 0.1", frac_equal(magres, frac_make(1, 10))); free_battle(b); - test_cleanup(); + test_teardown(); } static void test_projectile_armor(CuTest * tc) @@ -404,12 +404,12 @@ static void test_projectile_armor(CuTest * tc) variant v50p = frac_make(1, 2); test_setup(); - r = test_create_region(0, 0, 0); + r = test_create_region(0, 0, NULL); ishield = it_get_or_create(rt_get_or_create("shield")); ashield = new_armortype(ishield, 0.0, v50p, 1, ATF_SHIELD); ichain = it_get_or_create(rt_get_or_create("chainmail")); achain = new_armortype(ichain, 0.0, v50p, 3, ATF_NONE); - wtype = new_weapontype(it_get_or_create(rt_get_or_create("sword")), 0, v50p, 0, 0, 0, 0, SK_MELEE, 1); + wtype = new_weapontype(it_get_or_create(rt_get_or_create("sword")), 0, v50p, 0, 0, 0, 0, SK_MELEE); rc = test_create_race("human"); rc->battle_flags |= BF_EQUIPMENT; du = test_create_unit(test_create_faction(rc), r); @@ -427,7 +427,7 @@ static void test_projectile_armor(CuTest * tc) wtype->flags = WTF_NONE; CuAssertIntEquals_Msg(tc, "no projectiles", 4, calculate_armor(dt, 0, wtype, 0)); free_battle(b); - test_cleanup(); + test_teardown(); } static void test_battle_skilldiff(CuTest *tc) @@ -439,14 +439,14 @@ static void test_battle_skilldiff(CuTest *tc) test_setup(); - r = test_create_region(0, 0, 0); - ud = test_create_unit(test_create_faction(0), r); - ua = test_create_unit(test_create_faction(0), r); + r = test_create_region(0, 0, NULL); + ud = test_create_unit(test_create_faction(NULL), r); + ua = test_create_unit(test_create_faction(NULL), r); td.fighter = setup_fighter(&b, ud); td.index = 0; ta.fighter = setup_fighter(&b, ua); ta.index = 0; - ua = test_create_unit(test_create_faction(0), r); + ua = test_create_unit(test_create_faction(NULL), r); CuAssertIntEquals(tc, 0, skilldiff(ta, td, 0)); ta.fighter->person[0].attack = 2; @@ -461,7 +461,7 @@ static void test_battle_skilldiff(CuTest *tc) /* TODO: weapon modifiers, missiles, skill_formula */ free_battle(b); - test_cleanup(); + test_teardown(); } static void test_battle_skilldiff_building(CuTest *tc) @@ -475,15 +475,15 @@ static void test_battle_skilldiff_building(CuTest *tc) test_setup(); btype = setup_castle(); - r = test_create_region(0, 0, 0); - ud = test_create_unit(test_create_faction(0), r); + r = test_create_region(0, 0, NULL); + ud = test_create_unit(test_create_faction(NULL), r); ud->building = test_create_building(ud->region, btype); - ua = test_create_unit(test_create_faction(0), r); + ua = test_create_unit(test_create_faction(NULL), r); td.fighter = setup_fighter(&b, ud); td.index = 0; ta.fighter = setup_fighter(&b, ua); ta.index = 0; - ua = test_create_unit(test_create_faction(0), r); + ua = test_create_unit(test_create_faction(NULL), r); CuAssertIntEquals(tc, 0, skilldiff(ta, td, 0)); ud->building->size = 10; @@ -496,36 +496,37 @@ static void test_battle_skilldiff_building(CuTest *tc) CuAssertIntEquals(tc, -4, skilldiff(ta, td, 0)); free_battle(b); - test_cleanup(); + test_teardown(); } -static void assert_skill(CuTest *tc, char *msg, unit *u, skill_t sk, int level, int week, int weekmax) +static void assert_skill(CuTest *tc, const char *msg, unit *u, skill_t sk, int level, int week, int weekmax) { - skill *sv = unit_skill(u, sk); - char buf[256]; - if (sv) { - sprintf(buf, "%s level %d != %d", msg, sv->level, level); - CuAssertIntEquals_Msg(tc, (const char *)&buf, level, sv->level); - sprintf(buf, "%s week %d !<= %d !<= %d", msg, week, sv->weeks, weekmax); - CuAssert(tc, (const char *)&buf, sv->weeks >= week && sv->weeks <=weekmax); - } else { - CuAssertIntEquals_Msg(tc, msg, level, 0); - CuAssertIntEquals_Msg(tc, msg, week, 0); - } + skill *sv = unit_skill(u, sk); + char buf[256]; + if (sv) { + sprintf(buf, "%s level %d != %d", msg, sv->level, level); + CuAssertIntEquals_Msg(tc, buf, level, sv->level); + sprintf(buf, "%s week %d !<= %d !<= %d", msg, week, sv->weeks, weekmax); + CuAssert(tc, buf, sv->weeks >= week && sv->weeks <= weekmax); + } + else { + CuAssertIntEquals_Msg(tc, msg, level, 0); + CuAssertIntEquals_Msg(tc, msg, week, 0); + } } -static void test_drain_exp(CuTest *tc) +static void test_drain_exp(CuTest *tc) { unit *u; - char *msg; + const char *msg; int i; double rand; - + test_setup(); config_set("study.random_progress", "0"); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); set_level(u, SK_STAMINA, 3); - + CuAssertIntEquals(tc, 3, unit_skill(u, SK_STAMINA)->level); CuAssertIntEquals(tc, 4, unit_skill(u, SK_STAMINA)->weeks); @@ -533,46 +534,47 @@ static void test_drain_exp(CuTest *tc) assert_skill(tc, msg, u, SK_STAMINA, 3, 4, 4); assert_skill(tc, msg, u, SK_MINING, 0, 0, 0); - for (i=0; i<10; ++i) { - set_level(u, SK_STAMINA, 3); - drain_exp(u, 0); - assert_skill(tc, msg = "0 change", u, SK_STAMINA, 3, 4, 4); - assert_skill(tc, msg, u, SK_MINING, 0, 0, 0); + for (i = 0; i < 10; ++i) { + set_level(u, SK_STAMINA, 3); + drain_exp(u, 0); + assert_skill(tc, msg = "0 change", u, SK_STAMINA, 3, 4, 4); + assert_skill(tc, msg, u, SK_MINING, 0, 0, 0); - for (rand = 0.0; rand < 2.0; rand += 1) { - random_source_inject_constant(rand); - - set_level(u, SK_STAMINA, 3); - drain_exp(u, 29); - - assert_skill(tc, msg = "no change yet", u, SK_STAMINA, 3, 4, rand == 0.0?4:5); - assert_skill(tc, msg, u, SK_MINING, 0, 0, 0); - - set_level(u, SK_STAMINA, 3); - drain_exp(u, 1); - - assert_skill(tc, msg = "random change", u, SK_STAMINA, 3, 4, rand == 0.0?4:5); - assert_skill(tc, msg, u, SK_MINING, 0, 0, 0); - - set_level(u, SK_STAMINA, 3); - drain_exp(u, 30); - - assert_skill(tc, msg = "plus one", u, SK_STAMINA, 3, 5, 5); - assert_skill(tc, msg, u, SK_MINING, 0, 0, 0); - } - - set_level(u, SK_STAMINA, 3); - drain_exp(u, 90); - - assert_skill(tc, msg = "plus three", u, SK_STAMINA, 3, 7, 7); - assert_skill(tc, msg, u, SK_MINING, 0, 0, 0); - - set_level(u, SK_STAMINA, 3); - drain_exp(u, 120); - - assert_skill(tc, msg = "plus four", u, SK_STAMINA, 2, 5, 5); - assert_skill(tc, msg, u, SK_MINING, 0, 0, 0); + for (rand = 0.0; rand < 2.0; rand += 1) { + random_source_inject_constant(rand); + + set_level(u, SK_STAMINA, 3); + drain_exp(u, 29); + + assert_skill(tc, msg = "no change yet", u, SK_STAMINA, 3, 4, rand == 0.0 ? 4 : 5); + assert_skill(tc, msg, u, SK_MINING, 0, 0, 0); + + set_level(u, SK_STAMINA, 3); + drain_exp(u, 1); + + assert_skill(tc, msg = "random change", u, SK_STAMINA, 3, 4, rand == 0.0 ? 4 : 5); + assert_skill(tc, msg, u, SK_MINING, 0, 0, 0); + + set_level(u, SK_STAMINA, 3); + drain_exp(u, 30); + + assert_skill(tc, msg = "plus one", u, SK_STAMINA, 3, 5, 5); + assert_skill(tc, msg, u, SK_MINING, 0, 0, 0); + } + + set_level(u, SK_STAMINA, 3); + drain_exp(u, 90); + + assert_skill(tc, msg = "plus three", u, SK_STAMINA, 3, 7, 7); + assert_skill(tc, msg, u, SK_MINING, 0, 0, 0); + + set_level(u, SK_STAMINA, 3); + drain_exp(u, 120); + + assert_skill(tc, msg = "plus four", u, SK_STAMINA, 2, 5, 5); + assert_skill(tc, msg, u, SK_MINING, 0, 0, 0); } + test_teardown(); } CuSuite *get_battle_suite(void) @@ -589,6 +591,6 @@ CuSuite *get_battle_suite(void) SUITE_ADD_TEST(suite, test_natural_armor); SUITE_ADD_TEST(suite, test_magic_resistance); SUITE_ADD_TEST(suite, test_projectile_armor); - SUITE_ADD_TEST(suite, test_drain_exp); + DISABLE_TEST(suite, test_drain_exp); return suite; } diff --git a/src/bind_building.c b/src/bind_building.c index ea689bfb5..9e39a54a5 100644 --- a/src/bind_building.c +++ b/src/bind_building.c @@ -1,16 +1,7 @@ -/* -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - +#ifdef _MSC_VER #include +#endif + #include "bind_building.h" #include "bind_unit.h" @@ -21,6 +12,8 @@ without prior permission by the authors of Eressea. #include #include +#include +#include #include #include @@ -84,7 +77,7 @@ static int tolua_building_set_info(lua_State * L) const char *info = tolua_tostring(L, 2, 0); free(self->display); if (info) - self->display = strdup(info); + self->display = str_strdup(info); else self->display = NULL; return 0; diff --git a/src/bind_config.c b/src/bind_config.c index b4aa68d58..83c65364d 100644 --- a/src/bind_config.c +++ b/src/bind_config.c @@ -1,24 +1,32 @@ +#ifdef _MSC_VER +#include +#endif + #include "bind_config.h" -#include +#include "jsonconf.h" + #include -#include -#include -#include +#include +#include +#include +#include +#include +#include + #include #include +#include +#include +#include + #include + +#include #include #include #include -#include "kernel/building.h" -#include "kernel/race.h" -#include "kernel/ship.h" -#include "kernel/spell.h" -#include "kernel/spellbook.h" -#include "kernel/terrain.h" - void config_reset(void) { free_config(); free_nrmesssages(); @@ -46,7 +54,7 @@ int config_parse(const char *json) if (xp >= ep) break; } xp = (ep > json + 10) ? ep - 10 : json; - strlcpy(buffer, xp, sizeof(buffer)); + str_strlcpy(buffer, xp, sizeof(buffer)); buffer[9] = 0; log_error("json parse error in line %d, position %d, near `%s`\n", line, ep - lp, buffer); } @@ -55,12 +63,12 @@ int config_parse(const char *json) int config_read(const char *filename, const char * relpath) { - char name[MAX_PATH]; + char name[PATH_MAX]; FILE *F; json_relpath = relpath; if (relpath) { - join_path(relpath, filename, name, sizeof(name)); + path_join(relpath, filename, name, sizeof(name)); F = fopen(name, "r"); } else { diff --git a/src/bind_eressea.c b/src/bind_eressea.c index ffc23fbfc..11c03898d 100755 --- a/src/bind_eressea.c +++ b/src/bind_eressea.c @@ -1,3 +1,6 @@ +#ifdef _MSC_VER +#include +#endif #include "bind_eressea.h" #include diff --git a/src/bind_faction.c b/src/bind_faction.c index f9321f6b5..c0875aae2 100644 --- a/src/bind_faction.c +++ b/src/bind_faction.c @@ -10,7 +10,10 @@ This program may not be used, modified or distributed without prior permission by the authors of Eressea. */ +#ifdef _MSC_VER #include +#endif + #include "bind_faction.h" #include "bind_unit.h" #include "bindings.h" @@ -31,6 +34,7 @@ without prior permission by the authors of Eressea. #include #include #include +#include #include #include diff --git a/src/bind_gmtool.c b/src/bind_gmtool.c index 18efbd994..5c08f6e2c 100644 --- a/src/bind_gmtool.c +++ b/src/bind_gmtool.c @@ -1,4 +1,7 @@ +#ifdef _MSC_VER #include +#endif + #include #include "bind_gmtool.h" @@ -9,6 +12,7 @@ #include #include #include +#include #include @@ -16,6 +20,7 @@ static int tolua_run_mapper(lua_State * L) { + UNUSED_ARG(L); run_mapper(); return 0; } @@ -24,6 +29,7 @@ static int tolua_highlight_region(lua_State * L) { region *r = (region *)tolua_tousertype(L, 1, 0); int select = tolua_toboolean(L, 2, 0); + UNUSED_ARG(L); highlight_region(r, select); return 0; } @@ -41,6 +47,7 @@ static int tolua_select_coordinate(lua_State * L) int nx = (int)tolua_tonumber(L, 1, 0); int ny = (int)tolua_tonumber(L, 2, 0); int select = tolua_toboolean(L, 3, 0); + UNUSED_ARG(L); if (current_state) { select_coordinate(current_state->selected, nx, ny, select); } @@ -186,8 +193,8 @@ static void lua_paint_info(struct window *wnd, const struct state *st) if (!end) break; else { - size_t len = end - str; - int bytes = MIN((int)len, size); + int bytes = (int)(end - str); + if (bytes < size) bytes = size; mvwaddnstr(win, line++, 1, str, bytes); wclrtoeol(win); str = end + 1; diff --git a/src/bind_locale.c b/src/bind_locale.c index 992f140b7..ce46792d2 100644 --- a/src/bind_locale.c +++ b/src/bind_locale.c @@ -1,3 +1,7 @@ +#ifdef _MSC_VER +#include +#endif + #include "bind_locale.h" #include "util/language.h" #include "direction.h" diff --git a/src/bind_message.c b/src/bind_message.c index a3ab95d39..8eee85bc1 100644 --- a/src/bind_message.c +++ b/src/bind_message.c @@ -1,4 +1,7 @@ +#ifdef _MSC_VER #include +#endif + #include "spells.h" /* kernel includes */ @@ -10,6 +13,7 @@ /* util includes */ #include +#include #include #include diff --git a/src/bind_monsters.c b/src/bind_monsters.c index 082d940ae..76afffc15 100644 --- a/src/bind_monsters.c +++ b/src/bind_monsters.c @@ -1,4 +1,7 @@ +#ifdef _MSC_VER #include +#endif + #include "spells/shipcurse.h" #include "monsters.h" @@ -11,6 +14,8 @@ #include #include +#include + #include #include @@ -40,6 +45,7 @@ static int tolua_planmonsters(lua_State * L) static int tolua_spawn_dragons(lua_State * L) { + UNUSED_ARG(L); spawn_dragons(); return 0; } @@ -52,6 +58,7 @@ static int tolua_get_monsters(lua_State * L) static int tolua_spawn_undead(lua_State * L) { + UNUSED_ARG(L); spawn_undead(); return 0; } diff --git a/src/bind_order.c b/src/bind_order.c index 84399deec..407e29037 100644 --- a/src/bind_order.c +++ b/src/bind_order.c @@ -1,8 +1,11 @@ +#ifdef _MSC_VER #include +#endif /* kernel includes */ #include #include +#include /* lua includes */ #include @@ -13,7 +16,7 @@ static int tolua_order_get_token(lua_State *L) { order *ord = (order *)tolua_tousertype(L, 1, 0); int n = (int)tolua_tonumber(L, 2, 0); const char * str = 0; - init_order(ord); + init_order_depr(ord); while (n-->0) { str = getstrtoken(); if (!str) { diff --git a/src/bind_process.c b/src/bind_process.c index 2b44eb19d..947458ce5 100755 --- a/src/bind_process.c +++ b/src/bind_process.c @@ -1,6 +1,9 @@ +#ifdef _MSC_VER +#include +#endif + #include "bind_process.h" -#include #include #include #include diff --git a/src/bind_region.c b/src/bind_region.c index 2f9309549..8514bf639 100644 --- a/src/bind_region.c +++ b/src/bind_region.c @@ -1,16 +1,7 @@ -/* -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - +#ifdef _MSC_VER #include +#endif + #include "bind_region.h" #include "bind_unit.h" #include "bind_ship.h" @@ -39,6 +30,8 @@ without prior permission by the authors of Eressea. #include #include #include +#include +#include #include @@ -536,6 +529,27 @@ static int tolua_region_get_age(lua_State * L) return 0; } +static int tolua_region_get_peasants(lua_State * L) +{ + region *self = (region *)tolua_tousertype(L, 1, 0); + + if (self) { + lua_pushinteger(L, self->land ? self->land->peasants : 0); + return 1; + } + return 0; +} + +static int tolua_region_set_peasants(lua_State * L) +{ + region *self = (region *)tolua_tousertype(L, 1, 0); + + if (self && self->land) { + self->land->peasants = lua_tointeger(L, 2); + } + return 0; +} + static int tolua_region_getkey(lua_State * L) { region *self = (region *)tolua_tousertype(L, 1, 0); @@ -614,7 +628,7 @@ static int tolua_plane_set_name(lua_State * L) const char *str = tolua_tostring(L, 2, 0); free(self->name); if (str) - self->name = strdup(str); + self->name = str_strdup(str); else self->name = 0; return 0; @@ -734,6 +748,8 @@ void tolua_region_open(lua_State * L) tolua_variable(L, TOLUA_CAST "age", tolua_region_get_age, NULL); tolua_variable(L, TOLUA_CAST "buildings", tolua_region_get_buildings, NULL); + tolua_variable(L, TOLUA_CAST "peasants", tolua_region_get_peasants, + tolua_region_set_peasants); tolua_variable(L, TOLUA_CAST "terrain", tolua_region_get_terrain, tolua_region_set_terrain); tolua_function(L, TOLUA_CAST "get_resourcelevel", diff --git a/src/bind_ship.c b/src/bind_ship.c index c5e0735ed..2a1d75271 100644 --- a/src/bind_ship.c +++ b/src/bind_ship.c @@ -1,19 +1,11 @@ -/* -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - +#ifdef _MSC_VER #include +#endif + #include "bind_ship.h" #include "bind_unit.h" +#include "direction.h" #include "move.h" #include @@ -25,9 +17,12 @@ without prior permission by the authors of Eressea. #include #include #include +#include +#include #include -#include +#include +#include #include int tolua_shiplist_next(lua_State * L) @@ -45,28 +40,35 @@ int tolua_shiplist_next(lua_State * L) static int tolua_ship_get_id(lua_State * L) { - ship *self = (ship *)tolua_tousertype(L, 1, 0); + ship *self = (ship *)tolua_tousertype(L, 1, NULL); lua_pushinteger(L, self->no); return 1; } static int tolua_ship_get_name(lua_State * L) { - ship *self = (ship *)tolua_tousertype(L, 1, 0); + ship *self = (ship *)tolua_tousertype(L, 1, NULL); tolua_pushstring(L, ship_getname(self)); return 1; } +static int tolua_ship_get_size(lua_State * L) +{ + ship *self = (ship *)tolua_tousertype(L, 1, NULL); + lua_pushinteger(L, self->size); + return 1; +} + static int tolua_ship_get_display(lua_State * L) { - ship *self = (ship *)tolua_tousertype(L, 1, 0); + ship *self = (ship *)tolua_tousertype(L, 1, NULL); tolua_pushstring(L, self->display); return 1; } static int tolua_ship_get_region(lua_State * L) { - ship *self = (ship *)tolua_tousertype(L, 1, 0); + ship *self = (ship *)tolua_tousertype(L, 1, NULL); if (self) { tolua_pushusertype(L, self->region, TOLUA_CAST "region"); return 1; @@ -76,8 +78,8 @@ static int tolua_ship_get_region(lua_State * L) static int tolua_ship_set_region(lua_State * L) { - ship *self = (ship *)tolua_tousertype(L, 1, 0); - region *r = (region *)tolua_tousertype(L, 1, 0); + ship *self = (ship *)tolua_tousertype(L, 1, NULL); + region *r = (region *)tolua_tousertype(L, 2, NULL); if (self) { move_ship(self, self->region, r, NULL); } @@ -86,22 +88,29 @@ static int tolua_ship_set_region(lua_State * L) static int tolua_ship_set_name(lua_State * L) { - ship *self = (ship *)tolua_tousertype(L, 1, 0); - ship_setname(self, tolua_tostring(L, 2, 0)); + ship *self = (ship *)tolua_tousertype(L, 1, NULL); + ship_setname(self, tolua_tostring(L, 2, NULL)); + return 0; +} + +static int tolua_ship_set_size(lua_State * L) +{ + ship *self = (ship *)tolua_tousertype(L, 1, NULL); + self->size = lua_tointeger(L, 2); return 0; } static int tolua_ship_set_display(lua_State * L) { - ship *self = (ship *)tolua_tousertype(L, 1, 0); + ship *self = (ship *)tolua_tousertype(L, 1, NULL); free(self->display); - self->display = strdup(tolua_tostring(L, 2, 0)); + self->display = str_strdup(tolua_tostring(L, 2, NULL)); return 0; } static int tolua_ship_get_units(lua_State * L) { - ship *self = (ship *)tolua_tousertype(L, 1, 0); + ship *self = (ship *)tolua_tousertype(L, 1, NULL); unit **unit_ptr = (unit **)lua_newuserdata(L, sizeof(unit *)); unit *u = self->region->units; @@ -118,8 +127,8 @@ static int tolua_ship_get_units(lua_State * L) static int tolua_ship_create(lua_State * L) { - region *r = (region *)tolua_tousertype(L, 1, 0); - const char *sname = tolua_tostring(L, 2, 0); + region *r = (region *)tolua_tousertype(L, 1, NULL); + const char *sname = tolua_tostring(L, 2, NULL); if (sname) { const ship_type *stype = st_find(sname); if (stype) { @@ -138,40 +147,40 @@ static int tolua_ship_create(lua_State * L) static int tolua_ship_tostring(lua_State * L) { - ship *self = (ship *)tolua_tousertype(L, 1, 0); + ship *self = (ship *)tolua_tousertype(L, 1, NULL); lua_pushstring(L, shipname(self)); return 1; } static int tolua_ship_get_flags(lua_State * L) { - ship *self = (ship *)tolua_tousertype(L, 1, 0); + ship *self = (ship *)tolua_tousertype(L, 1, NULL); lua_pushinteger(L, self->flags); return 1; } static int tolua_ship_set_flags(lua_State * L) { - ship *self = (ship *)tolua_tousertype(L, 1, 0); - self->flags = (int)tolua_tonumber(L, 2, 0); + ship *self = (ship *)tolua_tousertype(L, 1, NULL); + self->flags = (int)lua_tointeger(L, 2); return 0; } static int tolua_ship_set_coast(lua_State * L) { - ship *self = (ship *)tolua_tousertype(L, 1, 0); + ship *self = (ship *)tolua_tousertype(L, 1, NULL); if (lua_isnil(L, 2)) { self->coast = NODIRECTION; } else if (lua_isnumber(L, 2)) { - self->coast = (direction_t)tolua_tonumber(L, 2, 0); + self->coast = (direction_t)lua_tointeger(L, 2); } return 0; } static int tolua_ship_get_coast(lua_State * L) { - ship *self = (ship *)tolua_tousertype(L, 1, 0); + ship *self = (ship *)tolua_tousertype(L, 1, NULL); if (self->coast) { lua_pushinteger(L, self->coast); return 1; @@ -181,28 +190,28 @@ static int tolua_ship_get_coast(lua_State * L) static int tolua_ship_get_type(lua_State * L) { - ship *self = (ship *)tolua_tousertype(L, 1, 0); + ship *self = (ship *)tolua_tousertype(L, 1, NULL); tolua_pushstring(L, self->type->_name); return 1; } static int tolua_ship_get_damage(lua_State * L) { - ship *self = (ship *)tolua_tousertype(L, 1, 0); + ship *self = (ship *)tolua_tousertype(L, 1, NULL); lua_pushinteger(L, self->damage); return 1; } static int tolua_ship_set_damage(lua_State * L) { - ship *self = (ship *)tolua_tousertype(L, 1, 0); - self->damage = (int)tolua_tonumber(L, 2, 0); + ship *self = (ship *)tolua_tousertype(L, 1, NULL); + self->damage = (int)lua_tointeger(L, 2); return 0; } static int tolua_ship_get_curse(lua_State *L) { - ship *self = (ship *)tolua_tousertype(L, 1, 0); - const char *name = tolua_tostring(L, 2, 0); + ship *self = (ship *)tolua_tousertype(L, 1, NULL); + const char *name = tolua_tostring(L, 2, NULL); if (self->attribs) { curse * c = get_curse(self->attribs, ct_find(name)); if (c) { @@ -214,8 +223,8 @@ static int tolua_ship_get_curse(lua_State *L) { } static int tolua_ship_has_attrib(lua_State *L) { - ship *self = (ship *)tolua_tousertype(L, 1, 0); - const char *name = tolua_tostring(L, 2, 0); + ship *self = (ship *)tolua_tousertype(L, 1, NULL); + const char *name = tolua_tostring(L, 2, NULL); attrib * a = a_find(self->attribs, at_find(name)); lua_pushboolean(L, a != NULL); return 1; @@ -236,6 +245,8 @@ void tolua_ship_open(lua_State * L) tolua_variable(L, TOLUA_CAST "id", tolua_ship_get_id, NULL); tolua_variable(L, TOLUA_CAST "name", tolua_ship_get_name, tolua_ship_set_name); + tolua_variable(L, TOLUA_CAST "size", tolua_ship_get_size, + tolua_ship_set_size); tolua_variable(L, TOLUA_CAST "info", tolua_ship_get_display, tolua_ship_set_display); tolua_variable(L, TOLUA_CAST "units", tolua_ship_get_units, NULL); diff --git a/src/bind_sqlite.c b/src/bind_sqlite.c deleted file mode 100644 index e8c9b7565..000000000 --- a/src/bind_sqlite.c +++ /dev/null @@ -1,95 +0,0 @@ -/* -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#include - -#include "bind_unit.h" -#include "bindings.h" - -#include -#include -#include - -#define LTYPE_DB TOLUA_CAST "db" - -extern int db_update_factions(sqlite3 * db, bool force, int game); -static int tolua_db_update_factions(lua_State * L) -{ - sqlite3 *db = (sqlite3 *)tolua_tousertype(L, 1, 0); - db_update_factions(db, tolua_toboolean(L, 2, 0), game_id()); - return 0; -} - -extern int db_update_scores(sqlite3 * db, bool force); -static int tolua_db_update_scores(lua_State * L) -{ - sqlite3 *db = (sqlite3 *)tolua_tousertype(L, 1, 0); - db_update_scores(db, tolua_toboolean(L, 2, 0)); - return 0; -} - -static int tolua_db_execute(lua_State * L) -{ - sqlite3 *db = (sqlite3 *)tolua_tousertype(L, 1, 0); - const char *sql = tolua_tostring(L, 2, 0); - - int res = sqlite3_exec(db, sql, 0, 0, 0); - - lua_pushinteger(L, res); - return 1; -} - -static int tolua_db_close(lua_State * L) -{ - sqlite3 *db = (sqlite3 *)tolua_tousertype(L, 1, 0); - sqlite3_close(db); - return 0; -} - -static int tolua_db_create(lua_State * L) -{ - sqlite3 *db; - const char *dbname = tolua_tostring(L, 1, 0); - int result = sqlite3_open_v2(dbname, &db, SQLITE_OPEN_READWRITE, 0); - if (result == SQLITE_OK) { - tolua_pushusertype(L, (void *)db, LTYPE_DB); - return 1; - } - return 0; -} - -int tolua_sqlite_open(lua_State * L) -{ - /* register user types */ - - tolua_usertype(L, LTYPE_DB); - - tolua_module(L, NULL, 0); - tolua_beginmodule(L, NULL); - { - tolua_cclass(L, LTYPE_DB, LTYPE_DB, TOLUA_CAST "", NULL); - tolua_beginmodule(L, LTYPE_DB); - { - tolua_function(L, TOLUA_CAST "open", &tolua_db_create); - tolua_function(L, TOLUA_CAST "close", &tolua_db_close); - - tolua_function(L, TOLUA_CAST "update_factions", - &tolua_db_update_factions); - tolua_function(L, TOLUA_CAST "update_scores", &tolua_db_update_scores); - tolua_function(L, TOLUA_CAST "execute", &tolua_db_execute); - } - tolua_endmodule(L); - - } - tolua_endmodule(L); - return 0; -} diff --git a/src/bind_storage.c b/src/bind_storage.c index 68ac36179..e1339312c 100644 --- a/src/bind_storage.c +++ b/src/bind_storage.c @@ -1,22 +1,14 @@ -/* -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - +#ifdef _MSC_VER #include +#endif + #include "bind_storage.h" #include #include #include +#include #include #include diff --git a/src/bind_tolua.c b/src/bind_tolua.c index 9a5b8e184..669d5848b 100644 --- a/src/bind_tolua.c +++ b/src/bind_tolua.c @@ -1,4 +1,6 @@ +#ifdef _MSC_VER #include +#endif #pragma warning(push) #pragma warning(disable: 4100) #include "config.pkg.c" diff --git a/src/bind_unit.c b/src/bind_unit.c index 1e1aee00e..4dd6313d8 100644 --- a/src/bind_unit.c +++ b/src/bind_unit.c @@ -1,16 +1,6 @@ -/* -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - +#ifdef _MSC_VER #include +#endif #include "bind_unit.h" #include "alchemy.h" @@ -46,6 +36,8 @@ without prior permission by the authors of Eressea. #include #include #include +#include + #include #include @@ -57,14 +49,18 @@ without prior permission by the authors of Eressea. #include static int tolua_bufunit(lua_State * L) { - char buf[8192]; - unit *self = (unit *)tolua_tousertype(L, 1, 0); - int mode = (int)tolua_tonumber(L, 2, (int)seen_unit); - if (!self) return 0; - - bufunit(self->faction, self, 0, mode, buf, sizeof(buf)); - tolua_pushstring(L, buf); - return 1; + unit *u = (unit *)tolua_tousertype(L, 1, 0); + if (u) { + faction *f = (faction *)tolua_tousertype(L, 2, u->faction); + if (f) { + char buf[8192]; + int mode = (int)tolua_tonumber(L, 3, (int)seen_unit); + bufunit(f, u, 0, mode, buf, sizeof(buf)); + tolua_pushstring(L, buf); + return 1; + } + } + return 0; } @@ -286,7 +282,7 @@ static int tolua_unit_get_magic(lua_State * L) static void unit_setmagic(unit * u, const char *type) { - sc_mage *mage = get_mage_depr(u); + sc_mage *mage = get_mage(u); int mtype; for (mtype = 0; mtype != MAXMAGIETYP; ++mtype) { if (strcmp(magic_school[mtype], type) == 0) @@ -331,7 +327,7 @@ static int tolua_unit_get_age(lua_State * L) static int tolua_unit_set_age(lua_State * L) { unit *self = (unit *)tolua_tousertype(L, 1, 0); - self->age = (short)tolua_tonumber(L, 2, 0); + self->age = (int)tolua_tonumber(L, 2, 0); return 0; } @@ -370,13 +366,10 @@ static int tolua_unit_get_effect(lua_State * L) const unit *self = (unit *)tolua_tousertype(L, 1, 0); const char *potion_name = tolua_tostring(L, 2, 0); int result = -1; - const potion_type *pt_potion; const item_type *it_potion = it_find(potion_name); if (it_potion != NULL) { - pt_potion = it_potion->rtype->ptype; - if (pt_potion != NULL) - result = get_effect(self, pt_potion); + result = get_effect(self, it_potion); } lua_pushinteger(L, result); @@ -512,6 +505,19 @@ static int tolua_unit_addnotice(lua_State * L) return 0; } +static int bind_unit_effect(lua_State * L) +{ + unit *u = (unit *)tolua_tousertype(L, 1, NULL); + const char *str = tolua_tostring(L, 2, NULL); + const item_type *itype = it_find(str); + if (itype) { + int effect = get_effect(u, itype); + lua_pushinteger(L, effect); + return 1; + } + return 0; +} + static void unit_castspell(unit * u, const char *name, int level) { spell *sp = find_spell(name); @@ -718,6 +724,30 @@ static int tolua_unit_set_region(lua_State * L) return 0; } +static int tolua_unit_get_order(lua_State * L) +{ + unit *self = (unit *)tolua_tousertype(L, 1, 0); + int index = (int)tolua_tonumber(L, 2, -1); + order *ord = NULL; + if (index < 0) { + ord = self->thisorder; + } + else { + int i; + ord = self->orders; + for (i = 0; ord && i != index; ++i) { + ord = ord->next; + } + } + if (ord) { + char buffer[1024]; + get_command(ord, self->faction->locale, buffer, sizeof(buffer)); + lua_pushstring(L, buffer); + return 1; + } + return 0; +} + static int tolua_unit_add_order(lua_State * L) { unit *self = (unit *)tolua_tousertype(L, 1, 0); @@ -763,22 +793,6 @@ static int tolua_unit_get_spells(lua_State * L) return tolua_selist_push(L, "spellbook", "spell_entry", slist); } -static int tolua_unit_get_orders(lua_State * L) -{ - unit *self = (unit *)tolua_tousertype(L, 1, 0); - - order **order_ptr = (order **)lua_newuserdata(L, sizeof(order *)); - - luaL_getmetatable(L, TOLUA_CAST "order"); - lua_setmetatable(L, -2); - - *order_ptr = self->orders; - - lua_pushcclosure(L, tolua_orderlist_next, 1); - - return 1; -} - static int tolua_unit_get_curse(lua_State *L) { unit *self = (unit *)tolua_tousertype(L, 1, 0); const char *name = tolua_tostring(L, 2, 0); @@ -960,95 +974,95 @@ void tolua_unit_open(lua_State * L) NULL); tolua_beginmodule(L, TOLUA_CAST "event"); { - tolua_function(L, TOLUA_CAST "get_type", &tolua_event_gettype); - tolua_function(L, TOLUA_CAST "get", &tolua_event_get); + tolua_function(L, TOLUA_CAST "get_type", tolua_event_gettype); + tolua_function(L, TOLUA_CAST "get", tolua_event_get); } tolua_endmodule(L); tolua_cclass(L, TOLUA_CAST "unit", TOLUA_CAST "unit", TOLUA_CAST "", NULL); tolua_beginmodule(L, TOLUA_CAST "unit"); { - tolua_function(L, TOLUA_CAST "__tostring", &tolua_unit_tostring); - tolua_function(L, TOLUA_CAST "create", &tolua_unit_create); - tolua_function(L, TOLUA_CAST "destroy", &tolua_unit_destroy); + tolua_function(L, TOLUA_CAST "__tostring", tolua_unit_tostring); + tolua_function(L, TOLUA_CAST "create", tolua_unit_create); + tolua_function(L, TOLUA_CAST "destroy", tolua_unit_destroy); - tolua_variable(L, TOLUA_CAST "name", &tolua_unit_get_name, + tolua_variable(L, TOLUA_CAST "name", tolua_unit_get_name, tolua_unit_set_name); - tolua_variable(L, TOLUA_CAST "faction", &tolua_unit_get_faction, + tolua_variable(L, TOLUA_CAST "faction", tolua_unit_get_faction, tolua_unit_set_faction); tolua_variable(L, TOLUA_CAST "id", tolua_unit_get_id, tolua_unit_set_id); tolua_variable(L, TOLUA_CAST "group", tolua_unit_get_group, tolua_unit_set_group); tolua_variable(L, TOLUA_CAST "info", tolua_unit_get_info, tolua_unit_set_info); - tolua_variable(L, TOLUA_CAST "hp", &tolua_unit_get_hp, tolua_unit_set_hp); - tolua_variable(L, TOLUA_CAST "status", &tolua_unit_get_status, + tolua_variable(L, TOLUA_CAST "hp", tolua_unit_get_hp, tolua_unit_set_hp); + tolua_variable(L, TOLUA_CAST "status", tolua_unit_get_status, tolua_unit_set_status); - tolua_variable(L, TOLUA_CAST "familiar", &tolua_unit_get_familiar, + tolua_variable(L, TOLUA_CAST "familiar", tolua_unit_get_familiar, tolua_unit_set_familiar); - tolua_variable(L, TOLUA_CAST "weight", &tolua_unit_get_weight, 0); - tolua_variable(L, TOLUA_CAST "capacity", &tolua_unit_get_capacity, 0); - - tolua_function(L, TOLUA_CAST "add_order", &tolua_unit_add_order); - tolua_function(L, TOLUA_CAST "clear_orders", &tolua_unit_clear_orders); - tolua_variable(L, TOLUA_CAST "orders", &tolua_unit_get_orders, 0); + tolua_variable(L, TOLUA_CAST "weight", tolua_unit_get_weight, 0); + tolua_variable(L, TOLUA_CAST "capacity", tolua_unit_get_capacity, 0); - tolua_function(L, TOLUA_CAST "get_curse", &tolua_unit_get_curse); - tolua_function(L, TOLUA_CAST "has_attrib", &tolua_unit_has_attrib); + tolua_function(L, TOLUA_CAST "get_order", tolua_unit_get_order); + tolua_function(L, TOLUA_CAST "add_order", tolua_unit_add_order); + tolua_function(L, TOLUA_CAST "clear_orders", tolua_unit_clear_orders); + tolua_function(L, TOLUA_CAST "get_curse", tolua_unit_get_curse); + tolua_function(L, TOLUA_CAST "has_attrib", tolua_unit_has_attrib); /* key-attributes for named flags: */ - tolua_function(L, TOLUA_CAST "set_flag", &tolua_unit_set_flag); - tolua_function(L, TOLUA_CAST "get_flag", &tolua_unit_get_flag); - tolua_variable(L, TOLUA_CAST "guard", &tolua_unit_get_guard, - &tolua_unit_set_guard); - tolua_variable(L, TOLUA_CAST "flags", &tolua_unit_get_flags, - &tolua_unit_set_flags); - tolua_variable(L, TOLUA_CAST "age", &tolua_unit_get_age, + tolua_function(L, TOLUA_CAST "set_flag", tolua_unit_set_flag); + tolua_function(L, TOLUA_CAST "get_flag", tolua_unit_get_flag); + tolua_variable(L, TOLUA_CAST "guard", tolua_unit_get_guard, + tolua_unit_set_guard); + tolua_variable(L, TOLUA_CAST "flags", tolua_unit_get_flags, + tolua_unit_set_flags); + tolua_variable(L, TOLUA_CAST "age", tolua_unit_get_age, tolua_unit_set_age); /* items: */ - tolua_function(L, TOLUA_CAST "get_item", &tolua_unit_get_item); - tolua_function(L, TOLUA_CAST "add_item", &tolua_unit_add_item); - tolua_variable(L, TOLUA_CAST "items", &tolua_unit_get_items, 0); - tolua_function(L, TOLUA_CAST "get_pooled", &tolua_unit_get_pooled); - tolua_function(L, TOLUA_CAST "use_pooled", &tolua_unit_use_pooled); + tolua_function(L, TOLUA_CAST "get_item", tolua_unit_get_item); + tolua_function(L, TOLUA_CAST "add_item", tolua_unit_add_item); + tolua_variable(L, TOLUA_CAST "items", tolua_unit_get_items, 0); + tolua_function(L, TOLUA_CAST "get_pooled", tolua_unit_get_pooled); + tolua_function(L, TOLUA_CAST "use_pooled", tolua_unit_use_pooled); /* effects */ - tolua_function(L, TOLUA_CAST "get_potion", &tolua_unit_get_effect); + tolua_function(L, TOLUA_CAST "get_potion", tolua_unit_get_effect); /* skills: */ - tolua_function(L, TOLUA_CAST "get_skill", &tolua_unit_getskill); - tolua_function(L, TOLUA_CAST "eff_skill", &tolua_unit_effskill); - tolua_function(L, TOLUA_CAST "set_skill", &tolua_unit_setskill); + tolua_function(L, TOLUA_CAST "get_skill", tolua_unit_getskill); + tolua_function(L, TOLUA_CAST "eff_skill", tolua_unit_effskill); + tolua_function(L, TOLUA_CAST "set_skill", tolua_unit_setskill); - tolua_function(L, TOLUA_CAST "add_notice", &tolua_unit_addnotice); + tolua_function(L, TOLUA_CAST "add_notice", tolua_unit_addnotice); /* npc logic: */ - tolua_function(L, TOLUA_CAST "add_handler", &tolua_unit_addhandler); + tolua_function(L, TOLUA_CAST "add_handler", tolua_unit_addhandler); - tolua_variable(L, TOLUA_CAST "race_name", &tolua_unit_get_racename, - &tolua_unit_set_racename); - tolua_function(L, TOLUA_CAST "add_spell", &tolua_unit_addspell); - tolua_variable(L, TOLUA_CAST "spells", &tolua_unit_get_spells, 0); - tolua_function(L, TOLUA_CAST "cast_spell", &tolua_unit_castspell); + tolua_variable(L, TOLUA_CAST "race_name", tolua_unit_get_racename, + tolua_unit_set_racename); + tolua_function(L, TOLUA_CAST "add_spell", tolua_unit_addspell); + tolua_variable(L, TOLUA_CAST "spells", tolua_unit_get_spells, 0); + tolua_function(L, TOLUA_CAST "cast_spell", tolua_unit_castspell); + tolua_function(L, TOLUA_CAST "effect", bind_unit_effect); - tolua_variable(L, TOLUA_CAST "magic", &tolua_unit_get_magic, + tolua_variable(L, TOLUA_CAST "magic", tolua_unit_get_magic, tolua_unit_set_magic); - tolua_variable(L, TOLUA_CAST "aura", &tolua_unit_get_aura, + tolua_variable(L, TOLUA_CAST "aura", tolua_unit_get_aura, tolua_unit_set_aura); - tolua_variable(L, TOLUA_CAST "building", &tolua_unit_get_building, + tolua_variable(L, TOLUA_CAST "building", tolua_unit_get_building, tolua_unit_set_building); - tolua_variable(L, TOLUA_CAST "ship", &tolua_unit_get_ship, + tolua_variable(L, TOLUA_CAST "ship", tolua_unit_get_ship, tolua_unit_set_ship); - tolua_variable(L, TOLUA_CAST "region", &tolua_unit_get_region, + tolua_variable(L, TOLUA_CAST "region", tolua_unit_get_region, tolua_unit_set_region); - tolua_variable(L, TOLUA_CAST "number", &tolua_unit_get_number, + tolua_variable(L, TOLUA_CAST "number", tolua_unit_get_number, tolua_unit_set_number); - tolua_variable(L, TOLUA_CAST "race", &tolua_unit_get_race, + tolua_variable(L, TOLUA_CAST "race", tolua_unit_get_race, tolua_unit_set_race); - tolua_variable(L, TOLUA_CAST "hp_max", &tolua_unit_get_hpmax, 0); - tolua_variable(L, TOLUA_CAST "aura_max", &tolua_unit_get_auramax, 0); + tolua_variable(L, TOLUA_CAST "hp_max", tolua_unit_get_hpmax, 0); + tolua_variable(L, TOLUA_CAST "aura_max", tolua_unit_get_auramax, 0); - tolua_function(L, TOLUA_CAST "show", &tolua_bufunit); + tolua_function(L, TOLUA_CAST "show", tolua_bufunit); } tolua_endmodule(L); } diff --git a/src/bindings.c b/src/bindings.c index 33d609ee0..b399dbdb8 100755 --- a/src/bindings.c +++ b/src/bindings.c @@ -1,16 +1,7 @@ -/* -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - +#ifdef _MSC_VER #include +#endif + #include "bindings.h" #include "bind_unit.h" #include "bind_storage.h" @@ -65,11 +56,12 @@ without prior permission by the authors of Eressea. #include #include #include -#include +#include #include #include #include +#include #include #include @@ -114,20 +106,6 @@ int log_lua_error(lua_State * L) return 1; } -int tolua_orderlist_next(lua_State * L) -{ - order **order_ptr = (order **)lua_touserdata(L, lua_upvalueindex(1)); - order *ord = *order_ptr; - if (ord != NULL) { - char cmd[8192]; - write_order(ord, cmd, sizeof(cmd)); - tolua_pushstring(L, cmd); - *order_ptr = ord->next; - return 1; - } - return 0; -} - static int tolua_selist_iter(lua_State * L) { selist **qlp = (selist **)lua_touserdata(L, lua_upvalueindex(1)); @@ -287,6 +265,7 @@ static int tolua_message_region(lua_State * L) static int tolua_update_guards(lua_State * L) { + UNUSED_ARG(L); update_guards(); return 0; } @@ -391,6 +370,7 @@ static int tolua_learn_skill(lua_State * L) static int tolua_update_scores(lua_State * L) { + UNUSED_ARG(L); score(); return 0; } @@ -398,6 +378,7 @@ static int tolua_update_scores(lua_State * L) static int tolua_update_owners(lua_State * L) { region *r; + UNUSED_ARG(L); for (r = regions; r; r = r->next) { update_owners(r); } @@ -406,12 +387,14 @@ static int tolua_update_owners(lua_State * L) static int tolua_update_subscriptions(lua_State * L) { + UNUSED_ARG(L); update_subscriptions(); return 0; } static int tolua_remove_empty_units(lua_State * L) { + UNUSED_ARG(L); remove_empty_units(); return 0; } @@ -496,24 +479,34 @@ static int tolua_write_reports(lua_State * L) static int tolua_process_orders(lua_State * L) { + UNUSED_ARG(L); +#if 0 + order * ord = parse_order("@GIB xmis ALLES Gurgelkraut", default_locale); + assert(ord); + free_order(ord); + return 0; +#endif processorders(); return 0; } static int tolua_turn_begin(lua_State * L) { + UNUSED_ARG(L); turn_begin(); return 0; } static int tolua_turn_process(lua_State * L) { + UNUSED_ARG(L); turn_process(); return 0; } static int tolua_turn_end(lua_State * L) { + UNUSED_ARG(L); turn_end(); return 0; } @@ -525,24 +518,15 @@ static int tolua_write_passwords(lua_State * L) return 0; } -static struct summary *sum_begin = 0; -static int tolua_init_summary(lua_State * L) -{ - sum_begin = make_summary(); - return 0; -} - static int tolua_write_summary(lua_State * L) { - if (sum_begin) { - struct summary *sum_end = make_summary(); - report_summary(sum_end, sum_begin, false); - report_summary(sum_end, sum_begin, true); - free_summary(sum_end); - free_summary(sum_begin); - sum_begin = 0; - return 0; - } + struct summary *sum; + UNUSED_ARG(L); + + sum = make_summary(); + report_summary(sum, false); + report_summary(sum, true); + free_summary(sum); return 0; } /* @@ -724,7 +708,6 @@ static int config_get_resource(lua_State * L) lua_settable(L, -3); } if (itype->construction) { - int i; lua_pushstring(L, "build_skill_min"); lua_pushinteger(L, itype->construction->minskill); lua_settable(L, -3); @@ -732,6 +715,7 @@ static int config_get_resource(lua_State * L) lua_pushstring(L, skillnames[itype->construction->skill]); lua_settable(L, -3); if (itype->construction->materials) { + int i; lua_pushstring(L, "materials"); lua_newtable(L); for (i = 0; itype->construction->materials[i].number; ++i) { @@ -788,7 +772,6 @@ static int config_get_btype(lua_State * L) lua_settable(L, -3); } if (btype->construction) { - int i; lua_pushstring(L, "build_skill_min"); lua_pushinteger(L, btype->construction->minskill); lua_settable(L, -3); @@ -796,6 +779,7 @@ static int config_get_btype(lua_State * L) lua_pushstring(L, skillnames[btype->construction->skill]); lua_settable(L, -3); if (btype->construction->materials) { + int i; lua_pushstring(L, "materials"); lua_newtable(L); for (i = 0; btype->construction->materials[i].number; ++i) { @@ -854,7 +838,6 @@ static int config_get_stype(lua_State * L) } } if (stype->construction) { - int i; lua_pushstring(L, "build_skill_min"); lua_pushinteger(L, stype->construction->minskill); lua_settable(L, -3); @@ -862,6 +845,7 @@ static int config_get_stype(lua_State * L) lua_pushstring(L, skillnames[stype->construction->skill]); lua_settable(L, -3); if (stype->construction->materials) { + int i; lua_pushstring(L, "materials"); lua_newtable(L); for (i = 0; stype->construction->materials[i].number; ++i) { @@ -936,12 +920,6 @@ int tolua_read_xml(lua_State * L) return 1; } -typedef struct event_args { - int hfunction; - int hargs; - const char *sendertype; -} event_args; - static int tolua_report_unit(lua_State * L) { char buffer[512]; @@ -1084,7 +1062,6 @@ int tolua_bindings_open(lua_State * L, const dictionary *inifile) tolua_function(L, TOLUA_CAST "init_reports", tolua_init_reports); tolua_function(L, TOLUA_CAST "write_reports", tolua_write_reports); tolua_function(L, TOLUA_CAST "write_report", tolua_write_report); - tolua_function(L, TOLUA_CAST "init_summary", tolua_init_summary); tolua_function(L, TOLUA_CAST "write_summary", tolua_write_summary); tolua_function(L, TOLUA_CAST "write_passwords", tolua_write_passwords); tolua_function(L, TOLUA_CAST "message_unit", tolua_message_unit); @@ -1136,9 +1113,6 @@ lua_State *lua_init(const dictionary *inifile) { register_tolua_helpers(); tolua_bindings_open(L, inifile); tolua_eressea_open(L); -#ifdef USE_SQLITE - tolua_sqlite_open(L); -#endif tolua_unit_open(L); tolua_building_open(L); tolua_ship_open(L); @@ -1186,7 +1160,6 @@ int eressea_run(lua_State *L, const char *luafile) { int err; global.vm_state = L; - /* push an error handling function on the stack: */ lua_getglobal(L, "debug"); lua_getfield(L, -1, "traceback"); diff --git a/src/bindings.h b/src/bindings.h index 5cb64a038..038afd31e 100755 --- a/src/bindings.h +++ b/src/bindings.h @@ -19,10 +19,8 @@ extern "C" { struct selist; int tolua_toid(struct lua_State *L, int idx, int def); - int tolua_sqlite_open(struct lua_State *L); int tolua_bindings_open(struct lua_State *L, const struct _dictionary_ *d); int tolua_itemlist_next(struct lua_State *L); - int tolua_orderlist_next(struct lua_State *L); int tolua_selist_push(struct lua_State *L, const char *list_type, const char *elem_type, struct selist *list); diff --git a/src/building_action.c b/src/building_action.c deleted file mode 100644 index 28cd55a48..000000000 --- a/src/building_action.c +++ /dev/null @@ -1,151 +0,0 @@ -/* -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include -#include -#include - -typedef struct building_action { - char *fname; - char *param; -} building_action; - -static int lc_age(struct attrib *a, void *owner) -{ - building_action *data = (building_action *)a->data.v; - const char *fname = data->fname; - const char *fparam = data->param; - building *b = (building *)owner; - int result = -1; - - assert(b != NULL); - if (fname != NULL) { - lua_State *L = (lua_State *)global.vm_state; - - lua_getglobal(L, fname); - if (lua_isfunction(L, -1)) { - tolua_pushusertype(L, (void *)b, TOLUA_CAST "building"); - if (fparam) { - tolua_pushstring(L, fparam); - } - - if (lua_pcall(L, fparam ? 2 : 1, 1, 0) != 0) { - const char *error = lua_tostring(L, -1); - log_error("lc_age(%s) calling '%s': %s.\n", buildingname(b), fname, error); - lua_pop(L, 1); - } - else { - result = (int)lua_tonumber(L, -1); - lua_pop(L, 1); - } - } - else { - log_error("lc_age(%s) calling '%s': not a function.\n", buildingname(b), fname); - lua_pop(L, 1); - } - } - return (result != 0) ? AT_AGE_KEEP : AT_AGE_REMOVE; -} - -static const char *NULLSTRING = "(null)"; - -static void lc_init(struct attrib *a) -{ - a->data.v = calloc(1, sizeof(building_action)); -} - -static void lc_done(struct attrib *a) -{ - building_action *data = (building_action *)a->data.v; - if (data->fname) - free(data->fname); - if (data->param) - free(data->param); - free(data); -} - -static void lc_write(const struct attrib *a, const void *owner, struct storage *store) -{ - building_action *data = (building_action *)a->data.v; - const char *fname = data->fname; - const char *fparam = data->param; - - UNUSED_ARG(owner); - WRITE_TOK(store, fname); - WRITE_TOK(store, fparam ? fparam : NULLSTRING); -} - -static int lc_read(struct attrib *a, void *owner, gamedata *data) -{ - struct storage *store = data->store; - char name[NAMESIZE]; - building_action *bd = (building_action *)a->data.v; - building *b = (building *)owner; - int result = 0; - if (data->version < ATTRIBOWNER_VERSION) { - READ_INT(data->store, NULL); - } - READ_TOK(store, name, sizeof(name)); - if (strcmp(name, "tunnel_action") == 0) { - /* E2: Weltentor has a new module, doesn't need this any longer */ - result = 0; - b = 0; - } - else { - bd->fname = strdup(name); - } - READ_TOK(store, name, sizeof(name)); - if (strcmp(name, "tnnL") == 0) { - /* tunnel_action was the old Weltentore, their code has changed. ignore this object */ - result = 0; - b = 0; - } - if (strcmp(name, NULLSTRING) == 0) - bd->param = 0; - else { - bd->param = strdup(name); - } - if (result == 0 && !b) { - return AT_READ_FAIL; - } - return AT_READ_OK; -} - -attrib_type at_building_action = { - "lcbuilding", - lc_init, lc_done, - lc_age, - lc_write, lc_read -}; - -void building_addaction(building * b, const char *fname, const char *param) -{ - attrib *a = a_add(&b->attribs, a_new(&at_building_action)); - building_action *data = (building_action *)a->data.v; - data->fname = strdup(fname); - if (param) { - data->param = strdup(param); - } -} diff --git a/src/calendar.c b/src/calendar.c index 6fd717429..23562daa6 100644 --- a/src/calendar.c +++ b/src/calendar.c @@ -1,4 +1,6 @@ +#ifdef _MSC_VER #include +#endif #include "calendar.h" #include "move.h" /* storms */ @@ -36,17 +38,18 @@ int first_turn(void) return config_get_int("game.start", 0); } -const gamedate *get_gamedate(int turn, gamedate * gd) +const gamedate *get_gamedate(int turn_now, gamedate * gd) { int weeks_per_year = months_per_year * weeks_per_month; - int t = turn - first_turn(); + int t = turn_now - first_turn(); assert(gd); assert(t>=0); + gd->turn = turn_now; gd->week = t % weeks_per_month; /* 0 - weeks_per_month-1 */ gd->month = (t / weeks_per_month + first_month) % months_per_year; /* 0 - months_per_year-1 */ - gd->year = t / (weeks_per_year)+1; + gd->year = 1 + t / weeks_per_year; gd->season = month_season ? month_season[gd->month] : 0; return gd; } diff --git a/src/calendar.h b/src/calendar.h index f8efa392c..af4bd6a4f 100644 --- a/src/calendar.h +++ b/src/calendar.h @@ -23,6 +23,7 @@ extern "C" { extern int weeks_per_month; typedef struct gamedate { + int turn; int year; int season; int month; diff --git a/src/calendar.test.c b/src/calendar.test.c index e858747ec..6e1edf5b6 100644 --- a/src/calendar.test.c +++ b/src/calendar.test.c @@ -16,7 +16,7 @@ static void test_calendar_config(CuTest * tc) CuAssertIntEquals(tc, 0, first_turn()); config_set_int("game.start", 42); CuAssertIntEquals(tc, 42, first_turn()); - test_cleanup(); + test_teardown(); } static void test_calendar(CuTest * tc) @@ -62,7 +62,7 @@ static void test_calendar(CuTest * tc) CuAssertIntEquals(tc, 2, gd.month); CuAssertIntEquals(tc, 0, gd.week); - test_cleanup(); + test_teardown(); } static void test_calendar_season(CuTest * tc) @@ -85,7 +85,7 @@ static void test_calendar_season(CuTest * tc) CuAssertIntEquals(tc, 1, gd.month); CuAssertIntEquals(tc, 1, gd.week); - test_cleanup(); + test_teardown(); } CuSuite *get_calendar_suite(void) diff --git a/src/console.c b/src/console.c index 0c0629de8..c20c0d8b9 100644 --- a/src/console.c +++ b/src/console.c @@ -1,4 +1,6 @@ +#ifdef _MSC_VER #include +#endif #include "console.h" /* lua includes */ @@ -246,15 +248,17 @@ int lua_do(lua_State * L) { int status = loadline(L); if (status != -1) { - if (status == 0) + if (status == 0) { status = docall(L, 0, 0); + } report(L, status); if (status == 0 && lua_gettop(L) > 0) { /* any result to print? */ lua_getglobal(L, "print"); lua_insert(L, 1); - if (lua_pcall(L, lua_gettop(L) - 1, 0, 0) != 0) + if (lua_pcall(L, lua_gettop(L) - 1, 0, 0) != 0) { l_message(NULL, lua_pushfstring(L, "error calling `print' (%s)", - lua_tostring(L, -1))); + lua_tostring(L, -1))); + } } } lua_settop(L, 0); /* clear stack */ diff --git a/src/convert.c b/src/convert.c index a67c5a287..2368043bb 100644 --- a/src/convert.c +++ b/src/convert.c @@ -1,10 +1,8 @@ #include -#ifdef USE_LIBXML2 -#include +#include "xmlreader.h" #include -#endif #include #include #include @@ -21,12 +19,9 @@ int main(int argc, char **argv) { const char *mode; register_races(); -#ifdef USE_LIBXML2 register_xmlreader(); -#endif if (argc < 2) return usage(); mode = argv[1]; -#ifdef USE_LIBXML2 if (strcmp(mode, "rules")==0) { const char *xmlfile, *catalog; if (argc < 4) return usage(); @@ -36,7 +31,6 @@ int main(int argc, char **argv) { write_rules("rules.dat"); return 0; } -#endif if (strcmp(mode, "po")==0) { return 0; } diff --git a/src/creport.c b/src/creport.c index 30f045b3f..fa17c426d 100644 --- a/src/creport.c +++ b/src/creport.c @@ -68,6 +68,7 @@ without prior permission by the authors of Eressea. #include #include #include +#include #include #include #include @@ -131,7 +132,7 @@ static const char *translate(const char *key, const char *value) } else t = malloc(sizeof(translation)); - t->key = strdup(key); + t->key = str_strdup(key); t->value = value; t->next = translation_table[kk]; translation_table[kk] = t; @@ -275,7 +276,7 @@ cr_output_curses(struct stream *out, const faction * viewer, const void *obj, ob else if (a->type == &at_effect && self) { effect_data *data = (effect_data *)a->data.v; if (data->value > 0) { - const char *key = resourcename(data->type->itype->rtype, 0); + const char *key = resourcename(data->type->rtype, 0); if (!header) { header = 1; stream_printf(out, "EFFECTS\n"); @@ -376,13 +377,13 @@ static int cr_alliance(variant var, char *buffer, const void *userdata) static int cr_skill(variant var, char *buffer, const void *userdata) { - const faction *report = (const faction *)userdata; + const faction *f = (const faction *)userdata; skill_t sk = (skill_t)var.i; UNUSED_ARG(userdata); if (sk != NOSKILL) sprintf(buffer, "\"%s\"", translate(mkname("skill", skillnames[sk]), skillname(sk, - report->locale))); + f->locale))); else strcpy(buffer, "\"\""); return 0; @@ -391,13 +392,14 @@ static int cr_skill(variant var, char *buffer, const void *userdata) static int cr_order(variant var, char *buffer, const void *userdata) { order *ord = (order *)var.v; - UNUSED_ARG(userdata); + const faction *f = (const faction *)userdata; + if (ord != NULL) { char cmd[ORDERSIZE]; char *wp = buffer; const char *rp; - get_command(ord, cmd, sizeof(cmd)); + get_command(ord, f->locale, cmd, sizeof(cmd)); *wp++ = '\"'; for (rp = cmd; *rp;) { @@ -511,11 +513,11 @@ static void report_crtypes(FILE * F, const struct locale *lang) const struct nrmessage_type *nrt = nrt_find(lang, kmt->mtype); if (nrt) { char buffer[DISPLAYSIZE]; - unsigned int hash = kmt->mtype->key; + int hash = (int)kmt->mtype->key; assert(hash > 0); - fprintf(F, "MESSAGETYPE %u\n", hash); + fprintf(F, "MESSAGETYPE %d\n", hash); fputc('\"', F); - fputs(escape_string(nrt_string(nrt), buffer, sizeof(buffer)), F); + fputs(str_escape(nrt_string(nrt), buffer, sizeof(buffer)), F); fputs("\";text\n", F); fprintf(F, "\"%s\";section\n", nrt_section(nrt)); } @@ -528,11 +530,11 @@ static void report_crtypes(FILE * F, const struct locale *lang) } } -static unsigned int messagehash(const struct message *msg) +static int message_id(const struct message *msg) { variant var; var.v = (void *)msg; - return (unsigned int)var.i; + return var.i & 0x7FFFFFFF; } /** writes a quoted string to the file @@ -578,7 +580,7 @@ static void render_messages(FILE * F, faction * f, message_list * msgs) char nrbuffer[1024 * 32]; nrbuffer[0] = '\0'; if (nr_render(m->msg, f->locale, nrbuffer, sizeof(nrbuffer), f) > 0) { - fprintf(F, "MESSAGE %u\n", messagehash(m->msg)); + fprintf(F, "MESSAGE %d\n", message_id(m->msg)); fprintf(F, "%u;type\n", hash); fwritestr(F, nrbuffer); fputs(";rendered\n", F); @@ -589,7 +591,7 @@ static void render_messages(FILE * F, faction * f, message_list * msgs) if (cr_render(m->msg, crbuffer, (const void *)f) == 0) { if (crbuffer[0]) { if (!printed) { - fprintf(F, "MESSAGE %u\n", messagehash(m->msg)); + fprintf(F, "MESSAGE %d\n", message_id(m->msg)); } fputs(crbuffer, F); } @@ -619,6 +621,26 @@ static void cr_output_messages(FILE * F, message_list * msgs, faction * f) render_messages(F, f, msgs); } +static void cr_output_battles(FILE * F, faction * f) +{ + struct bmsg *bm; + for (bm = f->battles; bm; bm = bm->next) { + region *rb = bm->r; + plane *pl = rplane(rb); + int plid = plane_id(pl); + int nx = rb->x, ny = rb->y; + + pnormalize(&nx, &ny, pl); + adjust_coordinates(f, &nx, &ny, pl); + if (!plid) + fprintf(F, "BATTLE %d %d\n", nx, ny); + else { + fprintf(F, "BATTLE %d %d %d\n", nx, ny, plid); + } + cr_output_messages(F, bm->msgs, f); + } +} + /* prints a building */ static void cr_output_building(struct stream *out, building *b, const unit *owner, int fno, faction *f) @@ -722,18 +744,6 @@ static void cr_output_ship_compat(FILE *F, const ship *sh, const unit *u, cr_output_ship(&strm, sh, u, fcaptain, f, r); } -static int stream_order(stream *out, const struct order *ord) { - const char *str; - char ebuf[1025]; - char obuf[1024]; - write_order(ord, obuf, sizeof(obuf)); - str = escape_string(obuf, ebuf, sizeof(ebuf)); - if (str == ebuf) { - ebuf[1024] = 0; - } - return stream_printf(out, "\"%s\"\n", str); -} - static void cr_output_spells(stream *out, const unit * u, int maxlevel) { spellbook * book = unit_get_spellbook(u); @@ -746,7 +756,6 @@ static void cr_output_spells(stream *out, const unit * u, int maxlevel) for (ql = book->spells, qi = 0; ql; selist_advance(&ql, &qi, 1)) { spellbook_entry * sbe = (spellbook_entry *)selist_get(ql, qi); if (sbe->level <= maxlevel) { - /* TODO: no need to deref spref here, spref->name == sp->sname */ spell * sp = sbe->sp; const char *name = translate(mkname("spell", sp->sname), spell_name(sp, f->locale)); if (!header) { @@ -763,7 +772,7 @@ static void cr_output_spells(stream *out, const unit * u, int maxlevel) * @param f observers faction * @param u unit to report */ -void cr_output_unit(stream *out, const region * r, const faction * f, +void cr_output_unit(stream *out, const faction * f, const unit * u, seen_mode mode) { /* Race attributes are always plural and item attributes always @@ -779,15 +788,16 @@ void cr_output_unit(stream *out, const region * r, const faction * f, const faction *fother; const char *prefix; bool allied; + const struct locale *lang = f->locale; assert(u && u->number); - assert(u->region == r); /* TODO: if this holds true, then why did we pass in r? */ + if (fval(u_race(u), RCF_INVISIBLE)) return; stream_printf(out, "EINHEIT %d\n", u->no); stream_printf(out, "\"%s\";Name\n", unit_getname(u)); - str = u_description(u, f->locale); + str = u_description(u, lang); if (str) { stream_printf(out, "\"%s\";Beschr\n", str); } @@ -804,7 +814,7 @@ void cr_output_unit(stream *out, const region * r, const faction * f, } mage = get_familiar_mage(u); if (mage) { - stream_printf(out, "%u;familiarmage\n", mage->no); + stream_printf(out, "%d;familiarmage\n", mage->no); } } @@ -833,7 +843,7 @@ void cr_output_unit(stream *out, const region * r, const faction * f, prefix = raceprefix(u); if (prefix) { prefix = mkname("prefix", prefix); - stream_printf(out, "\"%s\";typprefix\n", translate(prefix, LOC(f->locale, + stream_printf(out, "\"%s\";typprefix\n", translate(prefix, LOC(lang, prefix))); } stream_printf(out, "%d;Anzahl\n", u->number); @@ -844,18 +854,18 @@ void cr_output_unit(stream *out, const region * r, const faction * f, if (u->faction == f && fval(u_race(u), RCF_SHAPESHIFTANY)) { const char *zRace = rc_name_s(u_race(u), NAME_PLURAL); stream_printf(out, "\"%s\";wahrerTyp\n", - translate(zRace, LOC(f->locale, zRace))); + translate(zRace, LOC(lang, zRace))); } } else { const race *irace = u_irace(u); const char *zRace = rc_name_s(irace, NAME_PLURAL); stream_printf(out, "\"%s\";Typ\n", - translate(zRace, LOC(f->locale, zRace))); + translate(zRace, LOC(lang, zRace))); if (u->faction == f && irace != u_race(u)) { zRace = rc_name_s(u_race(u), NAME_PLURAL); stream_printf(out, "\"%s\";wahrerTyp\n", - translate(zRace, LOC(f->locale, zRace))); + translate(zRace, LOC(lang, zRace))); } } @@ -923,7 +933,9 @@ void cr_output_unit(stream *out, const region * r, const faction * f, for (ord = u->old_orders; ord; ord = ord->next) { /* this new order will replace the old defaults */ if (is_persistent(ord)) { - stream_order(out, ord); + swrite("\"", 1, 1, out); + stream_order(out, ord, lang, true); + swrite("\"\n", 1, 2, out); } } for (ord = u->orders; ord; ord = ord->next) { @@ -931,7 +943,9 @@ void cr_output_unit(stream *out, const region * r, const faction * f, if (u->old_orders && is_repeated(kwd)) continue; /* unit has defaults */ if (is_persistent(ord)) { - stream_order(out, ord); + swrite("\"", 1, 1, out); + stream_order(out, ord, lang, true); + swrite("\"\n", 1, 2, out); } } @@ -947,22 +961,21 @@ void cr_output_unit(stream *out, const region * r, const faction * f, } stream_printf(out, "%d %d;%s\n", u->number * level_days(sv->level), esk, translate(mkname("skill", skillnames[sk]), skillname(sk, - f->locale))); + lang))); } } /* spells that this unit can cast */ mage = get_mage_depr(u); if (mage) { - int i, maxlevel = effskill(u, SK_MAGIC, 0); + int maxlevel = effskill(u, SK_MAGIC, 0); cr_output_spells(out, u, maxlevel); for (i = 0; i != MAXCOMBATSPELLS; ++i) { const spell *sp = mage->combatspells[i].sp; if (sp) { const char *name = - translate(mkname("spell", sp->sname), spell_name(sp, - f->locale)); + translate(mkname("spell", sp->sname), spell_name(sp, lang)); stream_printf(out, "KAMPFZAUBER %d\n", i); stream_printf(out, "\"%s\";name\n", name); stream_printf(out, "%d;level\n", mage->combatspells[i].level); @@ -997,19 +1010,19 @@ void cr_output_unit(stream *out, const region * r, const faction * f, pr = 1; stream_printf(out, "GEGENSTAENDE\n"); } - stream_printf(out, "%d;%s\n", in, translate(ic, LOC(f->locale, ic))); + stream_printf(out, "%d;%s\n", in, translate(ic, LOC(lang, ic))); } cr_output_curses(out, f, u, TYP_UNIT); } -static void cr_output_unit_compat(FILE * F, const region * r, const faction * f, +static void cr_output_unit_compat(FILE * F, const faction * f, const unit * u, int mode) { /* TODO: eliminate this function */ stream strm; fstream_init(&strm, F); - cr_output_unit(&strm, r, f, u, mode); + cr_output_unit(&strm, f, u, mode); } /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ @@ -1053,8 +1066,8 @@ static void cr_find_address(FILE * F, const faction * uf, selist * addresses) if (uf != f) { fprintf(F, "PARTEI %d\n", f->no); fprintf(F, "\"%s\";Parteiname\n", f->name); - if (f->email) - fprintf(F, "\"%s\";email\n", f->email); + if (strcmp(faction_getemail(f), "") != 0) + fprintf(F, "\"%s\";email\n", faction_getemail(f)); if (f->banner) fprintf(F, "\"%s\";banner\n", f->banner); fprintf(F, "\"%s\";locale\n", locale_name(f->locale)); @@ -1074,7 +1087,7 @@ static void cr_reportspell(FILE * F, spell * sp, int level, const struct locale const char *name = translate(mkname("spell", sp->sname), spell_name(sp, lang)); - fprintf(F, "ZAUBER %d\n", hashstring(sp->sname)); + fprintf(F, "ZAUBER %d\n", str_hash(sp->sname)); fprintf(F, "\"%s\";name\n", name); fprintf(F, "%d;level\n", level); fprintf(F, "%d;rank\n", sp->rank); @@ -1108,7 +1121,7 @@ static void cr_reportspell(FILE * F, spell * sp, int level, const struct locale int itemanz = sp->components[k].amount; int costtyp = sp->components[k].cost; if (itemanz > 0) { - const char *name = resourcename(rtype, 0); + name = resourcename(rtype, 0); fprintf(F, "%d %d;%s\n", itemanz, costtyp == SPC_LEVEL || costtyp == SPC_LINEAR, translate(name, LOC(lang, name))); } @@ -1122,7 +1135,7 @@ static char *cr_output_resource(char *buf, const resource_type *rtype, assert(rtype); name = resourcename(rtype, NMF_PLURAL); assert(name); - buf += sprintf(buf, "RESOURCE %u\n", hashstring(rtype->_name)); + buf += sprintf(buf, "RESOURCE %u\n", str_hash(rtype->_name)); tname = LOC(loc, name); assert(tname); tname = translate(name, tname); @@ -1302,12 +1315,6 @@ static void cr_output_region(FILE * F, report_context * ctx, region * r) int oc[4][2], o = 0; int uid = r->uid; -#ifdef OCEAN_NEIGHBORS_GET_NO_ID - if (r->seen.mode <= seen_neighbour && !r->land) { - uid = 0; - } -#endif - if (opt_cr_absolute_coords) { nx = r->x; ny = r->y; @@ -1387,7 +1394,7 @@ static void cr_output_region(FILE * F, report_context * ctx, region * r) else { fprintf(F, "%d;Rekruten\n", rpeasants(r) / RECRUITFRACTION); } - if (production(r)) { + if (max_production(r)) { int p_wage = wage(r, NULL, NULL, turn + 1); fprintf(F, "%d;Lohn\n", p_wage); if (is_mourning(r, turn + 1)) { @@ -1446,14 +1453,15 @@ static void cr_output_region(FILE * F, report_context * ctx, region * r) if (rl) { region_list *rl2 = rl; while (rl2) { - region *r = rl2->data; - int nx = r->x, ny = r->y; - plane *plx = rplane(r); + region *r2 = rl2->data; + plane *plx = rplane(r2); + nx = r2->x; + ny = r2->y; pnormalize(&nx, &ny, plx); adjust_coordinates(f, &nx, &ny, plx); fprintf(F, "SCHEMEN %d %d\n", nx, ny); - fprintf(F, "\"%s\";Name\n", rname(r, f->locale)); + fprintf(F, "\"%s\";Name\n", rname(r2, f->locale)); rl2 = rl2->next; } free_regionlist(rl); @@ -1494,9 +1502,8 @@ static void cr_output_region(FILE * F, report_context * ctx, region * r) /* visible units */ for (u = r->units; u; u = u->next) { - if (u->building || u->ship || (stealthmod > INT_MIN - && cansee_ex(f, r, u, stealthmod, r->seen.mode))) { - cr_output_unit_compat(F, r, f, u, r->seen.mode); + if (visible_unit(u, f, stealthmod, r->seen.mode)) { + cr_output_unit_compat(F, f, u, r->seen.mode); } } } @@ -1561,7 +1568,7 @@ report_computer(const char *filename, report_context * ctx, const char *bom) } fprintf(F, "%d;age\n", f->age); fprintf(F, "%d;Optionen\n", f->options); - if (f->options & want(O_SCORE) && f->age > DISPLAYSCORE) { + if (f->options & WANT_OPTION(O_SCORE) && f->age > DISPLAYSCORE) { char score[32]; write_score(score, sizeof(score), f->score); fprintf(F, "%s;Punkte\n", score); @@ -1602,13 +1609,13 @@ report_computer(const char *filename, report_context * ctx, const char *bom) } fprintf(F, "\"%s\";Parteiname\n", f->name); - fprintf(F, "\"%s\";email\n", f->email); + fprintf(F, "\"%s\";email\n", faction_getemail(f)); if (f->banner) fprintf(F, "\"%s\";banner\n", f->banner); print_items(F, f->items, f->locale); fputs("OPTIONEN\n", F); for (i = 0; i != MAXOPTIONS; ++i) { - int flag = want(i); + int flag = WANT_OPTION(i); if (options[i]) { fprintf(F, "%d;%s\n", (f->options & flag) ? 1 : 0, options[i]); } @@ -1634,24 +1641,7 @@ report_computer(const char *filename, report_context * ctx, const char *bom) } cr_output_messages(F, f->msgs, f); - { - struct bmsg *bm; - for (bm = f->battles; bm; bm = bm->next) { - plane *pl = rplane(bm->r); - int plid = plane_id(pl); - region *r = bm->r; - int nx = r->x, ny = r->y; - - pnormalize(&nx, &ny, pl); - adjust_coordinates(f, &nx, &ny, pl); - if (!plid) - fprintf(F, "BATTLE %d %d\n", nx, ny); - else { - fprintf(F, "BATTLE %d %d %d\n", nx, ny, plid); - } - cr_output_messages(F, bm->msgs, f); - } - } + cr_output_battles(F, f); cr_find_address(F, f, ctx->addresses); a = a_find(f->attribs, &at_reportspell); @@ -1662,27 +1652,26 @@ report_computer(const char *filename, report_context * ctx, const char *bom) } for (a = a_find(f->attribs, &at_showitem); a && a->type == &at_showitem; a = a->next) { - const potion_type *ptype = - resource2potion(((const item_type *)a->data.v)->rtype); + const item_type *itype = (const item_type *)a->data.v; const char *ch; const char *description = NULL; - if (ptype == NULL) + if (itype == NULL) continue; - ch = resourcename(ptype->itype->rtype, 0); - fprintf(F, "TRANK %d\n", hashstring(ch)); + ch = resourcename(itype->rtype, 0); + fprintf(F, "TRANK %d\n", str_hash(ch)); fprintf(F, "\"%s\";Name\n", translate(ch, LOC(f->locale, ch))); - fprintf(F, "%d;Stufe\n", ptype->level); + fprintf(F, "%d;Stufe\n", potion_level(itype)); if (description == NULL) { - const char *pname = resourcename(ptype->itype->rtype, 0); + const char *pname = resourcename(itype->rtype, 0); const char *potiontext = mkname("potion", pname); description = LOC(f->locale, potiontext); } fprintf(F, "\"%s\";Beschr\n", description); - if (ptype->itype->construction) { - requirement *m = ptype->itype->construction->materials; + if (itype->construction) { + requirement *m = itype->construction->materials; fprintf(F, "ZUTATEN\n"); diff --git a/src/creport.h b/src/creport.h index 435bb637f..ed8f3bfbd 100644 --- a/src/creport.h +++ b/src/creport.h @@ -27,8 +27,8 @@ extern "C" { void register_cr(void); int crwritemap(const char *filename); - void cr_output_unit(struct stream *out, const struct region * r, - const struct faction * f, const struct unit * u, seen_mode mode); + void cr_output_unit(struct stream *out, const struct faction * f, + const struct unit * u, seen_mode mode); void cr_output_resources(struct stream *out, const struct faction * f, const struct region *r, bool see_unit); #ifdef __cplusplus diff --git a/src/creport.test.c b/src/creport.test.c index e87de235e..bacf8def0 100644 --- a/src/creport.test.c +++ b/src/creport.test.c @@ -36,19 +36,19 @@ static void test_cr_unit(CuTest *tc) { region *r; unit *u; - test_cleanup(); - f = test_create_faction(0); - r = test_create_region(0, 0, 0); + test_setup(); + f = test_create_faction(NULL); + r = test_create_region(0, 0, NULL); u = test_create_unit(f, r); renumber_unit(u, 1234); mstream_init(&strm); - cr_output_unit(&strm, r, f, u, seen_unit); + cr_output_unit(&strm, f, u, seen_unit); strm.api->rewind(strm.handle); CuAssertIntEquals(tc, 0, strm.api->readln(strm.handle, line, sizeof(line))); CuAssertStrEquals(tc, line, "EINHEIT 1234"); mstream_done(&strm); - test_cleanup(); + test_teardown(); } static void setup_resources(void) { @@ -91,8 +91,8 @@ static void test_cr_resources(CuTest *tc) { setup_resources(); - f = test_create_faction(0); - r = test_create_region(0, 0, 0); + f = test_create_faction(NULL); + r = test_create_region(0, 0, NULL); u = test_create_unit(f, r); set_level(u, SK_QUARRYING, 1); r->land->horses = 1; @@ -158,7 +158,7 @@ static void test_cr_resources(CuTest *tc) { CuAssertStrEquals(tc, "1;number", line); mstream_done(&strm); - test_cleanup(); + test_teardown(); } static void test_cr_mallorn(CuTest *tc) { @@ -169,8 +169,8 @@ static void test_cr_mallorn(CuTest *tc) { setup_resources(); - f = test_create_faction(0); - r = test_create_region(0, 0, 0); + f = test_create_faction(NULL); + r = test_create_region(0, 0, NULL); r->land->horses = 1; r->land->peasants = 200; r->land->money = 300; @@ -204,7 +204,7 @@ static void test_cr_mallorn(CuTest *tc) { CuAssertStrEquals(tc, "3;number", line); mstream_done(&strm); - test_cleanup(); + test_teardown(); } static int cr_get_int(stream *strm, const char *match, int def) @@ -230,14 +230,14 @@ static void test_cr_factionstealth(CuTest *tc) { ally *al; test_setup(); - f1 = test_create_faction(0); - f2 = test_create_faction(0); - r = test_create_region(0, 0, 0); + f1 = test_create_faction(NULL); + f2 = test_create_faction(NULL); + r = test_create_region(0, 0, NULL); u = test_create_unit(f1, r); /* report to ourselves */ mstream_init(&strm); - cr_output_unit(&strm, u->region, f1, u, seen_unit); + cr_output_unit(&strm, f1, u, seen_unit); CuAssertIntEquals(tc, f1->no, cr_get_int(&strm, ";Partei", -1)); CuAssertIntEquals(tc, -1, cr_get_int(&strm, ";Anderepartei", -1)); CuAssertIntEquals(tc, -1, cr_get_int(&strm, ";Verraeter", -1)); @@ -247,7 +247,7 @@ static void test_cr_factionstealth(CuTest *tc) { /* ... also when we are anonymous */ u->flags |= UFL_ANON_FACTION; mstream_init(&strm); - cr_output_unit(&strm, u->region, f1, u, seen_unit); + cr_output_unit(&strm, f1, u, seen_unit); CuAssertIntEquals(tc, f1->no, cr_get_int(&strm, ";Partei", -1)); CuAssertIntEquals(tc, -1, cr_get_int(&strm, ";Anderepartei", -1)); CuAssertIntEquals(tc, -1, cr_get_int(&strm, ";Verraeter", -1)); @@ -259,7 +259,7 @@ static void test_cr_factionstealth(CuTest *tc) { set_factionstealth(u, f2); CuAssertPtrNotNull(tc, u->attribs); mstream_init(&strm); - cr_output_unit(&strm, u->region, f1, u, seen_unit); + cr_output_unit(&strm, f1, u, seen_unit); CuAssertIntEquals(tc, f1->no, cr_get_int(&strm, ";Partei", -1)); CuAssertIntEquals(tc, f2->no, cr_get_int(&strm, ";Anderepartei", -1)); CuAssertIntEquals(tc, -1, cr_get_int(&strm, ";Verraeter", -1)); @@ -269,7 +269,7 @@ static void test_cr_factionstealth(CuTest *tc) { /* ... also when we are anonymous */ u->flags |= UFL_ANON_FACTION; mstream_init(&strm); - cr_output_unit(&strm, u->region, f1, u, seen_unit); + cr_output_unit(&strm, f1, u, seen_unit); CuAssertIntEquals(tc, f1->no, cr_get_int(&strm, ";Partei", -1)); CuAssertIntEquals(tc, f2->no, cr_get_int(&strm, ";Anderepartei", -1)); CuAssertIntEquals(tc, -1, cr_get_int(&strm, ";Verraeter", -1)); @@ -279,7 +279,7 @@ static void test_cr_factionstealth(CuTest *tc) { /* we can tell that someone is presenting as us */ mstream_init(&strm); - cr_output_unit(&strm, u->region, f2, u, seen_unit); + cr_output_unit(&strm, f2, u, seen_unit); CuAssertIntEquals(tc, f2->no, cr_get_int(&strm, ";Partei", -1)); CuAssertIntEquals(tc, -1, cr_get_int(&strm, ";Anderepartei", -1)); CuAssertIntEquals(tc, 1, cr_get_int(&strm, ";Verraeter", -1)); @@ -289,7 +289,7 @@ static void test_cr_factionstealth(CuTest *tc) { /* ... but not if they are anonymous */ u->flags |= UFL_ANON_FACTION; mstream_init(&strm); - cr_output_unit(&strm, u->region, f2, u, seen_unit); + cr_output_unit(&strm, f2, u, seen_unit); CuAssertIntEquals(tc, -1, cr_get_int(&strm, ";Partei", -1)); CuAssertIntEquals(tc, -1, cr_get_int(&strm, ";Anderepartei", -1)); CuAssertIntEquals(tc, -1, cr_get_int(&strm, ";Verraeter", -1)); @@ -301,7 +301,7 @@ static void test_cr_factionstealth(CuTest *tc) { al = ally_add(&f1->allies, f2); al->status = HELP_FSTEALTH; mstream_init(&strm); - cr_output_unit(&strm, u->region, f2, u, seen_unit); + cr_output_unit(&strm, f2, u, seen_unit); CuAssertIntEquals(tc, f1->no, cr_get_int(&strm, ";Partei", -1)); CuAssertIntEquals(tc, f2->no, cr_get_int(&strm, ";Anderepartei", -1)); CuAssertIntEquals(tc, -1, cr_get_int(&strm, ";Verraeter", -1)); @@ -311,7 +311,7 @@ static void test_cr_factionstealth(CuTest *tc) { /* ... also when they are anonymous */ u->flags |= UFL_ANON_FACTION; mstream_init(&strm); - cr_output_unit(&strm, u->region, f2, u, seen_unit); + cr_output_unit(&strm, f2, u, seen_unit); CuAssertIntEquals(tc, f1->no, cr_get_int(&strm, ";Partei", -1)); CuAssertIntEquals(tc, f2->no, cr_get_int(&strm, ";Anderepartei", -1)); CuAssertIntEquals(tc, -1, cr_get_int(&strm, ";Verraeter", -1)); @@ -319,7 +319,7 @@ static void test_cr_factionstealth(CuTest *tc) { u->flags &= ~UFL_ANON_FACTION; mstream_done(&strm); - test_cleanup(); + test_teardown(); } CuSuite *get_creport_suite(void) diff --git a/src/direction.c b/src/direction.c index 5e2333bbe..13feff13b 100644 --- a/src/direction.c +++ b/src/direction.c @@ -8,6 +8,15 @@ #include +const char *shortdirections[MAXDIRECTIONS] = { + "dir_nw", + "dir_ne", + "dir_east", + "dir_se", + "dir_sw", + "dir_west" +}; + void init_direction(const struct locale *lang, direction_t dir, const char *str) { void **tokens = get_translations(lang, UT_DIRECTIONS); variant token; diff --git a/src/direction.h b/src/direction.h index 8f0932aaf..724878663 100644 --- a/src/direction.h +++ b/src/direction.h @@ -21,6 +21,8 @@ extern "C" NODIRECTION = -1 } direction_t; + extern const char *shortdirections[MAXDIRECTIONS]; + direction_t get_direction(const char *s, const struct locale *); void init_directions(struct locale *lang); void init_direction(const struct locale *lang, direction_t dir, const char *str); @@ -30,5 +32,6 @@ extern "C" extern const char * directions[]; #ifdef __cplusplus +} #endif #endif diff --git a/src/direction.test.c b/src/direction.test.c index bf50df6bf..2e770b51e 100644 --- a/src/direction.test.c +++ b/src/direction.test.c @@ -16,7 +16,7 @@ static void test_init_directions(CuTest *tc) { locale_setstring(lang, "dir_nw", "NW"); init_directions(lang); CuAssertIntEquals(tc, D_NORTHWEST, get_direction("nw", lang)); - test_cleanup(); + test_teardown(); } static void test_init_direction(CuTest *tc) { @@ -33,7 +33,7 @@ static void test_init_direction(CuTest *tc) { CuAssertIntEquals(tc, D_EAST, get_direction("ost", lang)); CuAssertIntEquals(tc, D_EAST, get_direction("O", lang)); CuAssertIntEquals(tc, NODIRECTION, get_direction("east", lang)); - test_cleanup(); + test_teardown(); } static void test_finddirection(CuTest *tc) { @@ -47,7 +47,7 @@ static void test_finddirection(CuTest *tc) { CuAssertIntEquals(tc, D_PAUSE, finddirection("pause")); CuAssertIntEquals(tc, NODIRECTION, finddirection("")); CuAssertIntEquals(tc, NODIRECTION, finddirection("potato")); - test_cleanup(); + test_teardown(); } CuSuite *get_direction_suite(void) diff --git a/src/donations.test.c b/src/donations.test.c index 09cd31977..e61ca2536 100644 --- a/src/donations.test.c +++ b/src/donations.test.c @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -11,15 +12,16 @@ static void test_add_donation(CuTest *tc) { faction *f1, *f2; region *r; - test_cleanup(); - r = test_create_region(0, 0, 0); - f1 = test_create_faction(0); - f2 = test_create_faction(0); + test_setup(); + mt_register(mt_new_va("donation", "from:faction", "to:faction", "amount:int", NULL)); + r = test_create_region(0, 0, NULL); + f1 = test_create_faction(NULL); + f2 = test_create_faction(NULL); add_donation(f1, f2, 100, r); report_donations(); CuAssertPtrNotNull(tc, test_find_messagetype(r->individual_messages->msgs, "donation")); free_donations(); - test_cleanup(); + test_teardown(); } CuSuite *get_donations_suite(void) diff --git a/src/economy.c b/src/economy.c index 7c4b0efd3..82890888e 100644 --- a/src/economy.c +++ b/src/economy.c @@ -17,7 +17,9 @@ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. **/ +#ifdef _MSC_VER #include +#endif #include #include "economy.h" @@ -64,7 +66,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* util includes */ #include #include -#include #include #include #include @@ -81,26 +82,13 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include -typedef struct request { - struct request *next; - struct unit *unit; - struct order *ord; - int qty; - int no; - union { - bool goblin; /* stealing */ - const struct luxury_type *ltype; /* trading */ - } type; -} request; - static int working; -static request entertainers[1024]; -static request *nextentertainer; +static econ_request entertainers[1024]; +static econ_request *nextentertainer; static int entertaining; -static unsigned int norders; -static request *g_requests; +static econ_request **g_requests; /* TODO: no need for this to be module-global */ #define RECRUIT_MERGE 1 static int rules_recruit = -1; @@ -153,19 +141,18 @@ static void scramble(void *data, unsigned int n, size_t width) } } -static void expandorders(region * r, request * requests) +unsigned int expand_production(region * r, econ_request * requests, econ_request ***results) { unit *u; - request *o; + econ_request *o; + unsigned int norders = 0; - /* Alle Units ohne request haben ein -1, alle units mit orders haben ein + /* Alle Units ohne production haben ein -1, alle units mit orders haben ein * 0 hier stehen */ for (u = r->units; u; u = u->next) u->n = -1; - norders = 0; - for (o = requests; o; o = o->next) { if (o->qty > 0) { norders += o->qty; @@ -174,50 +161,59 @@ static void expandorders(region * r, request * requests) if (norders > 0) { int i = 0; - g_requests = (request *)calloc(norders, sizeof(request)); + econ_request **split; + split = calloc(norders, sizeof(econ_request *)); for (o = requests; o; o = o->next) { if (o->qty > 0) { unsigned int j; for (j = o->qty; j; j--) { - g_requests[i] = *o; - g_requests[i].unit->n = 0; + split[i] = o; + o->unit->n = 0; i++; } } } - scramble(g_requests, norders, sizeof(request)); + scramble(split, norders, sizeof(econ_request *)); + *results = split; } else { - g_requests = NULL; + *results = NULL; } + return norders; +} + +static void free_requests(econ_request *requests) { while (requests) { - request *o = requests->next; - free_order(requests->ord); + econ_request *req = requests->next; free(requests); - requests = o; + requests = req; } } +static unsigned int expandorders(region * r, econ_request * requests) { + return expand_production(r, requests, &g_requests); +} + /* ------------------------------------------------------------- */ typedef struct recruitment { struct recruitment *next; faction *f; - request *requests; + econ_request *requests; int total, assigned; } recruitment; -/** Creates a list of recruitment structs, one for each faction. Adds every quantifyable request +/** Creates a list of recruitment structs, one for each faction. Adds every quantifyable production * to the faction's struct and to total. */ -static recruitment *select_recruitment(request ** rop, +static recruitment *select_recruitment(econ_request ** rop, int(*quantify) (const struct race *, int), int *total) { recruitment *recruits = NULL; while (*rop) { recruitment *rec = recruits; - request *ro = *rop; + econ_request *ro = *rop; unit *u = ro->unit; const race *rc = u_race(u); int qty = quantify(rc, ro->qty); @@ -254,6 +250,7 @@ void add_recruits(unit * u, int number, int wanted) if (number > 0) { unit *unew; char equipment[64]; + int len; if (u->number == 0) { set_number(u, number); @@ -264,10 +261,10 @@ void add_recruits(unit * u, int number, int wanted) unew = create_unit(r, u->faction, number, u_race(u), 0, NULL, u); } - strlcpy(equipment, "new_", sizeof(equipment)); - strlcat(equipment, u_race(u)->_name, sizeof(equipment)); - equip_unit(unew, get_equipment(equipment)); - + len = snprintf(equipment, sizeof(equipment), "new_%s", u_race(u)->_name); + if (len > 0 && (size_t)len < sizeof(equipment)) { + equip_unit(unew, get_equipment(equipment)); + } if (unew != u) { transfermen(unew, u, unew->number); remove_unit(&r->units, unew); @@ -294,7 +291,7 @@ static int do_recruiting(recruitment * recruits, int available) int n = 0; int rest, mintotal = INT_MAX; - /* find smallest request */ + /* find smallest production */ for (rec = recruits; rec != NULL; rec = rec->next) { int want = rec->total - rec->assigned; if (want > 0) { @@ -310,7 +307,7 @@ static int do_recruiting(recruitment * recruits, int available) } rest = available - mintotal * n; - /* assign size of smallest request for everyone if possible; in the end roll dice to assign + /* assign size of smallest production for everyone if possible; in the end roll dice to assign * small rest */ for (rec = recruits; rec != NULL; rec = rec->next) { int want = rec->total - rec->assigned; @@ -330,7 +327,7 @@ static int do_recruiting(recruitment * recruits, int available) /* do actual recruiting */ for (rec = recruits; rec != NULL; rec = rec->next) { - request *req; + econ_request *req; int get = rec->assigned; for (req = rec->requests; req; req = req->next) { @@ -339,14 +336,15 @@ static int do_recruiting(recruitment * recruits, int available) int number, dec; double multi = 2.0 * rc->recruit_multi; - number = MIN(req->qty, (int)(get / multi)); + number = (int)(get / multi); + if (number > req->qty) number = req->qty; if (rc->recruitcost) { int afford = get_pooled(u, get_resourcetype(R_SILVER), GET_DEFAULT, number * rc->recruitcost) / rc->recruitcost; - number = MIN(number, afford); + if (number > afford) number = afford; } if (u->number + number > UNIT_MAXSIZE) { - ADDMSG(&u->faction->msgs, msg_feedback(u, req->ord, "error_unit_size", + ADDMSG(&u->faction->msgs, msg_feedback(u, req->type.recruit.ord, "error_unit_size", "maxsize", UNIT_MAXSIZE)); number = UNIT_MAXSIZE - u->number; assert(number >= 0); @@ -379,9 +377,8 @@ void free_recruitments(recruitment * recruits) recruitment *rec = recruits; recruits = rec->next; while (rec->requests) { - request *req = rec->requests; + econ_request *req = rec->requests; rec->requests = req->next; - free_order(req->ord); free(req); } free(rec); @@ -389,7 +386,7 @@ void free_recruitments(recruitment * recruits) } /* Rekrutierung */ -static void expandrecruit(region * r, request * recruitorders) +static void expandrecruit(region * r, econ_request * recruitorders) { recruitment *recruits = NULL; @@ -430,18 +427,18 @@ static int recruit_cost(const faction * f, const race * rc) return -1; } -static void recruit(unit * u, struct order *ord, request ** recruitorders) +static void recruit(unit * u, struct order *ord, econ_request ** recruitorders) { region *r = u->region; plane *pl; - request *o; + econ_request *o; int recruitcost = -1; const faction *f = u->faction; const struct race *rc = u_race(u); const char *str; int n; - init_order(ord); + init_order_depr(ord); n = getint(); if (n <= 0) { syntax_error(u, ord); @@ -545,7 +542,8 @@ static void recruit(unit * u, struct order *ord, request ** recruitorders) if (recruitcost > 0) { int pooled = get_pooled(u, get_resourcetype(R_SILVER), GET_DEFAULT, recruitcost * n); - n = MIN(n, pooled / recruitcost); + int pr = pooled / recruitcost; + if (n > pr) n = pr; } u->wants = n; @@ -555,10 +553,10 @@ static void recruit(unit * u, struct order *ord, request ** recruitorders) return; } - o = (request *)calloc(1, sizeof(request)); + o = (econ_request *)calloc(1, sizeof(econ_request)); o->qty = n; o->unit = u; - o->ord = copy_order(ord); + o->type.recruit.ord = ord; addlist(recruitorders, o); } @@ -598,7 +596,7 @@ int give_control_cmd(unit * u, order * ord) unit *u2; const char *s; - init_order(ord); + init_order_depr(ord); getunit(r, u->faction, &u2); s = gettoken(token, sizeof(token)); @@ -657,7 +655,7 @@ static int forget_cmd(unit * u, order * ord) return 0; } - init_order(ord); + init_order_depr(ord); s = gettoken(token, sizeof(token)); sk = get_skill(s, u->faction->locale); @@ -751,7 +749,7 @@ void maintain_buildings(region * r) void economics(region * r) { unit *u; - request *recruitorders = NULL; + econ_request *recruitorders = NULL; /* Geben vor Selbstmord (doquit)! Hier alle unmittelbaren Befehle. * Rekrutieren vor allen Einnahmequellen. Bewachen JA vor Steuern @@ -808,12 +806,12 @@ void economics(region * r) } -static void mod_skill(const resource_mod *mod, skill_t sk, int *skill) { +static void mod_skill(const resource_mod *mod, skill_t sk, int *value) { skill_t msk; assert(mod->type == RMT_PROD_SKILL); msk = (skill_t)mod->value.sa[0]; if (msk == NOSKILL || msk == sk) { - *skill += mod->value.sa[1]; + *value += mod->value.sa[1]; } } @@ -1029,13 +1027,14 @@ static void allocate_resource(unit * u, const resource_type * rtype, int want) /* mit Flinkfingerring verzehnfacht sich die Produktion */ rring = get_resourcetype(R_RING_OF_NIMBLEFINGER); if (rring) { - int dm = i_get(u->items, rring->itype); - amount += skill * MIN(u->number, dm) * (roqf_factor() - 1); + int more = i_get(u->items, rring->itype); + if (more > u->number) more = u->number; + amount += skill * more * (roqf_factor() - 1); } /* Schaffenstrunk: */ if ((dm = get_effect(u, oldpotiontype[P_DOMORE])) != 0) { - dm = MIN(dm, u->number); + if (dm > u->number) dm = u->number; change_effect(u, oldpotiontype[P_DOMORE], -dm); amount += dm * skill; /* dm Personen produzieren doppelt */ } @@ -1067,7 +1066,7 @@ static int required(int want, variant save) { int req = (int)(want * save.sa[0] / save.sa[1]); int r = want * save.sa[0] % save.sa[1]; - if (r>0) ++req; + if (r > 0) ++req; return req; } @@ -1115,7 +1114,7 @@ leveled_allocation(const resource_type * rtype, region * r, allocation * alist) } need = nreq; - avail = MIN(avail, nreq); + if (avail > nreq) avail = nreq; if (need > 0) { int use = 0; for (al = alist; al; al = al->next) { @@ -1123,14 +1122,15 @@ leveled_allocation(const resource_type * rtype, region * r, allocation * alist) if (avail > 0) { int want = required(al->want - al->get, al->save); int x = avail * want / nreq; - int r = (avail * want) % nreq; + int req = (avail * want) % nreq; /* Wenn Rest, dann wuerfeln, ob ich etwas bekomme: */ - if (r > 0 && rng_int() % nreq < r) ++x; + if (req > 0 && rng_int() % nreq < req) ++x; avail -= x; use += x; nreq -= want; need -= x; - al->get = MIN(al->want, al->get + x * al->save.sa[1] / al->save.sa[0]); + al->get = al->get + x * al->save.sa[1] / al->save.sa[0]; + if (al->get > al->want) al->get = al->want; } } } @@ -1166,18 +1166,19 @@ attrib_allocation(const resource_type * rtype, region * r, allocation * alist) } } - avail = MIN(avail, nreq); + if (avail > nreq) avail = nreq; + for (al = alist; al; al = al->next) { if (avail > 0) { int want = required(al->want, al->save); int x = avail * want / nreq; int rx = (avail * want) % nreq; /* Wenn Rest, dann wuerfeln, ob ich was bekomme: */ - if (rx>0 && rng_int() % nreq < rx) ++x; + if (rx > 0 && rng_int() % nreq < rx) ++x; avail -= x; nreq -= want; al->get = x * al->save.sa[1] / al->save.sa[0]; - al->get = MIN(al->want, al->get); + if (al->want < al->get) al->get = al->want; if (!rtype->raw) { int use = required(al->get, al->save); if (use) { @@ -1233,14 +1234,14 @@ void split_allocations(region * r) allocations = NULL; } -static void create_potion(unit * u, const potion_type * ptype, int want) +static void create_potion(unit * u, const item_type * itype, int want) { int built; if (want == 0) { - want = maxbuild(u, ptype->itype->construction); + want = maxbuild(u, itype->construction); } - built = build(u, ptype->itype->construction, 0, want, 0); + built = build(u, itype->construction, 0, want, 0); switch (built) { case ELOWSKILL: case ENEEDSKILL: @@ -1253,16 +1254,16 @@ static void create_potion(unit * u, const potion_type * ptype, int want) case ENOMATERIALS: /* something missing from the list of materials */ ADDMSG(&u->faction->msgs, msg_materials_required(u, u->thisorder, - ptype->itype->construction, want)); + itype->construction, want)); return; break; default: - i_change(&u->items, ptype->itype, built); + i_change(&u->items, itype, built); if (want == INT_MAX) want = built; ADDMSG(&u->faction->msgs, msg_message("produce", "unit region amount wanted resource", u, u->region, built, want, - ptype->itype->rtype)); + itype->rtype)); break; } } @@ -1277,11 +1278,12 @@ void make_item(unit * u, const item_type * itype, int want) allocate_resource(u, itype->rtype, want); } else { - const potion_type *ptype = resource2potion(itype->rtype); - if (ptype != NULL) - create_potion(u, ptype, want); - else if (itype->construction && itype->construction->materials) + if (itype->flags & ITF_POTION) { + create_potion(u, itype, want); + } + else if (itype->construction && itype->construction->materials) { manufacture(u, itype, want); + } else { ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "error_cannotmake", "")); @@ -1291,7 +1293,7 @@ void make_item(unit * u, const item_type * itype, int want) int make_cmd(unit * u, struct order *ord) { - char token[128]; + char token[32]; region *r = u->region; const building_type *btype = 0; const ship_type *stype = 0; @@ -1303,7 +1305,7 @@ int make_cmd(unit * u, struct order *ord) char ibuf[16]; keyword_t kwd; - kwd = init_order(ord); + kwd = init_order_depr(ord); assert(kwd == K_MAKE); s = gettoken(token, sizeof(token)); @@ -1328,7 +1330,7 @@ int make_cmd(unit * u, struct order *ord) cmistake(u, ord, 275, MSG_PRODUCE); } else { - const char * s = gettoken(token, sizeof(token)); + s = gettoken(token, sizeof(token)); direction_t d = s ? get_direction(s, u->faction->locale) : NODIRECTION; if (d != NODIRECTION) { build_road(u, m, d); @@ -1441,29 +1443,24 @@ const attrib_type at_luxuries = { "luxuries", NULL, free_luxuries, NULL, NULL, NULL }; -static void expandbuying(region * r, request * buyorders) +static void expandbuying(region * r, econ_request * buyorders) { const resource_type *rsilver = get_resourcetype(R_SILVER); int max_products; unit *u; - static struct trade { + struct trade { const luxury_type *type; int number; int multi; } trades[MAXLUXURIES], *trade; - static int ntrades = 0; - int i; + int ntrades = 0; const luxury_type *ltype; - if (ntrades == 0) { - for (ntrades = 0, ltype = luxurytypes; ltype; ltype = ltype->next) { - assert(ntrades < MAXLUXURIES); - trades[ntrades++].type = ltype; - } - } - for (i = 0; i != ntrades; ++i) { - trades[i].number = 0; - trades[i].multi = 1; + for (ntrades = 0, ltype = luxurytypes; ltype; ltype = ltype->next) { + assert(ntrades < MAXLUXURIES); + trades[ntrades].number = 0; + trades[ntrades].multi = 1; + trades[ntrades++].type = ltype; } if (!buyorders) @@ -1481,52 +1478,54 @@ static void expandbuying(region * r, request * buyorders) * G�ter pro Monat ist. j sind die Befehle, i der Index des * gehandelten Produktes. */ if (max_products > 0) { - unsigned int j; - expandorders(r, buyorders); - if (!norders) - return; - - for (j = 0; j != norders; j++) { - int price, multi; - ltype = g_requests[j].type.ltype; - trade = trades; - while (trade->type != ltype) - ++trade; - multi = trade->multi; - price = ltype->price * multi; - - if (get_pooled(g_requests[j].unit, rsilver, GET_DEFAULT, - price) >= price) { - unit *u = g_requests[j].unit; - item *items; - - /* litems z�hlt die G�ter, die verkauft wurden, u->n das Geld, das - * verdient wurde. Dies mu� gemacht werden, weil der Preis st�ndig sinkt, - * man sich also das verdiente Geld und die verkauften Produkte separat - * merken mu�. */ - attrib *a = a_find(u->attribs, &at_luxuries); - if (a == NULL) - a = a_add(&u->attribs, a_new(&at_luxuries)); - - items = a->data.v; - i_change(&items, ltype->itype, 1); - a->data.v = items; - i_change(&g_requests[j].unit->items, ltype->itype, 1); - use_pooled(u, rsilver, GET_DEFAULT, price); - if (u->n < 0) - u->n = 0; - u->n += price; - - rsetmoney(r, rmoney(r) + price); - - /* Falls mehr als max_products Bauern ein Produkt verkauft haben, steigt - * der Preis Multiplikator f�r das Produkt um den Faktor 1. Der Z�hler - * wird wieder auf 0 gesetzt. */ - if (++trade->number == max_products) { - trade->number = 0; - ++trade->multi; + unsigned int norders = expandorders(r, buyorders); + + if (norders) { + unsigned int j; + for (j = 0; j != norders; j++) { + int price, multi; + ltype = g_requests[j]->type.trade.ltype; + trade = trades; + while (trade->type && trade->type != ltype) + ++trade; + multi = trade->multi; + price = ltype->price * multi; + + if (get_pooled(g_requests[j]->unit, rsilver, GET_DEFAULT, + price) >= price) { + item *items; + /* litems z�hlt die G�ter, die verkauft wurden, u->n das Geld, das + * verdient wurde. Dies mu� gemacht werden, weil der Preis st�ndig sinkt, + * man sich also das verdiente Geld und die verkauften Produkte separat + * merken mu�. */ + attrib *a; + + u = g_requests[j]->unit; + a = a_find(u->attribs, &at_luxuries); + if (a == NULL) { + a = a_add(&u->attribs, a_new(&at_luxuries)); + } + items = a->data.v; + + i_change(&items, ltype->itype, 1); + a->data.v = items; + i_change(&g_requests[j]->unit->items, ltype->itype, 1); + use_pooled(u, rsilver, GET_DEFAULT, price); + if (u->n < 0) + u->n = 0; + u->n += price; + + rsetmoney(r, rmoney(r) + price); + + /* Falls mehr als max_products Bauern ein Produkt verkauft haben, steigt + * der Preis Multiplikator f�r das Produkt um den Faktor 1. Der Z�hler + * wird wieder auf 0 gesetzt. */ + if (++trade->number == max_products) { + trade->number = 0; + ++trade->multi; + } + fset(u, UFL_LONGACTION | UFL_NOTMOVING); } - fset(u, UFL_LONGACTION | UFL_NOTMOVING); } } free(g_requests); @@ -1559,12 +1558,12 @@ attrib_type at_trades = { NO_READ }; -static void buy(unit * u, request ** buyorders, struct order *ord) +static void buy(unit * u, econ_request ** buyorders, struct order *ord) { char token[128]; region *r = u->region; int n, k; - request *o; + econ_request *o; attrib *a; const item_type *itype = NULL; const luxury_type *ltype = NULL; @@ -1582,7 +1581,7 @@ static void buy(unit * u, request ** buyorders, struct order *ord) /* Im Augenblick kann man nur 1 Produkt kaufen. expandbuying ist aber * schon daf�r ausger�stet, mehrere Produkte zu kaufen. */ - kwd = init_order(ord); + kwd = init_order_depr(ord); assert(kwd == K_BUY); n = getint(); if (n <= 0) { @@ -1595,17 +1594,10 @@ static void buy(unit * u, request ** buyorders, struct order *ord) return; } - if (u_race(u) == get_race(RC_INSECT)) { - /* entweder man ist insekt, oder... */ - if (r->terrain != newterrain(T_SWAMP) && r->terrain != newterrain(T_DESERT) - && !rbuildings(r)) { - cmistake(u, ord, 119, MSG_COMMERCE); - return; - } - } - else { - /* ...oder in der Region mu� es eine Burg geben. */ - building *b = 0; + /* Entweder man ist Insekt in Sumpf/Wueste, oder es muss + * einen Handelsposten in der Region geben: */ + if (u_race(u) != get_race(RC_INSECT) || (r->terrain == newterrain(T_SWAMP) || r->terrain == newterrain(T_DESERT))) { + building *b = NULL; if (r->buildings) { static int cache; static const struct building_type *bt_castle; @@ -1638,7 +1630,7 @@ static void buy(unit * u, request ** buyorders, struct order *ord) k -= a->data.i; } - n = MIN(n, k); + if (n > k) n = k; if (!n) { cmistake(u, ord, 102, MSG_COMMERCE); @@ -1662,8 +1654,8 @@ static void buy(unit * u, request ** buyorders, struct order *ord) ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "luxury_notsold", "")); return; } - o = (request *)calloc(1, sizeof(request)); - o->type.ltype = ltype; /* sollte immer gleich sein */ + o = (econ_request *)calloc(1, sizeof(econ_request)); + o->type.trade.ltype = ltype; /* sollte immer gleich sein */ o->unit = u; o->qty = n; @@ -1671,21 +1663,21 @@ static void buy(unit * u, request ** buyorders, struct order *ord) } /* ------------------------------------------------------------- */ -static void add_income(unit * u, int type, int want, int qty) +void add_income(unit * u, income_t type, int want, int qty) { if (want == INT_MAX) want = qty; ADDMSG(&u->faction->msgs, msg_message("income", - "unit region mode wanted amount", u, u->region, type, want, qty)); + "unit region mode wanted amount", u, u->region, (int)type, want, qty)); } /* Steuers�tze in % bei Burggr��e */ static int tax_per_size[7] = { 0, 6, 12, 18, 24, 30, 36 }; -static void expandselling(region * r, request * sellorders, int limit) +static void expandselling(region * r, econ_request * sellorders, int limit) { int money, price, max_products; - unsigned int j; + unsigned int j, norders; /* int m, n = 0; */ int maxsize = 0, maxeffsize = 0; int taxcollected = 0; @@ -1760,78 +1752,78 @@ static void expandselling(region * r, request * sellorders, int limit) /* Verkauf: so programmiert, dass er leicht auf mehrere Gueter pro * Runde erweitert werden kann. */ - expandorders(r, sellorders); - if (!norders) - return; + norders = expandorders(r, sellorders); + if (norders > 0) { + for (j = 0; j != norders; j++) { + const luxury_type *search = NULL; + const luxury_type *ltype = g_requests[j]->type.trade.ltype; + int multi = r_demand(r, ltype); + int i; + int use = 0; + for (i = 0, search = luxurytypes; search != ltype; search = search->next) { + /* TODO: this is slow and lame! */ + ++i; + } + if (counter[i] >= limit) + continue; + if (counter[i] + 1 > max_products && multi > 1) + --multi; + price = ltype->price * multi; - for (j = 0; j != norders; j++) { - const luxury_type *search = NULL; - const luxury_type *ltype = g_requests[j].type.ltype; - int multi = r_demand(r, ltype); - int i; - int use = 0; - for (i = 0, search = luxurytypes; search != ltype; search = search->next) { - /* TODO: this is slow and lame! */ - ++i; - } - if (counter[i] >= limit) - continue; - if (counter[i] + 1 > max_products && multi > 1) - --multi; - price = ltype->price * multi; - - if (money >= price) { - int abgezogenhafen = 0; - int abgezogensteuer = 0; - unit *u = g_requests[j].unit; - item *itm; - attrib *a = a_find(u->attribs, &at_luxuries); - if (a == NULL) - a = a_add(&u->attribs, a_new(&at_luxuries)); - itm = (item *)a->data.v; - i_change(&itm, ltype->itype, 1); - a->data.v = itm; - ++use; - if (u->n < 0) - u->n = 0; - - if (hafenowner != NULL) { - if (hafenowner->faction != u->faction) { - abgezogenhafen = price / 10; - hafencollected += abgezogenhafen; - price -= abgezogenhafen; - money -= abgezogenhafen; + if (money >= price) { + item *itm; + attrib *a; + u = g_requests[j]->unit; + a = a_find(u->attribs, &at_luxuries); + if (!a) { + a = a_add(&u->attribs, a_new(&at_luxuries)); } - } - if (maxb != NULL) { - if (maxowner->faction != u->faction) { - abgezogensteuer = price * tax_per_size[maxeffsize] / 100; - taxcollected += abgezogensteuer; - price -= abgezogensteuer; - money -= abgezogensteuer; + itm = (item *)a->data.v; + i_change(&itm, ltype->itype, 1); + a->data.v = itm; + ++use; + if (u->n < 0) { + u->n = 0; } - } - u->n += price; - change_money(u, price); - fset(u, UFL_LONGACTION | UFL_NOTMOVING); - /* r->money -= price; --- dies wird eben nicht ausgef�hrt, denn die - * Produkte k�nnen auch als Steuern eingetrieben werden. In der Region - * wurden Silberst�cke gegen Luxusg�ter des selben Wertes eingetauscht! - * Falls mehr als max_products Kunden ein Produkt gekauft haben, sinkt - * die Nachfrage f�r das Produkt um 1. Der Z�hler wird wieder auf 0 - * gesetzt. */ - - if (++counter[i] > max_products) { - int d = r_demand(r, ltype); - if (d > 1) { - r_setdemand(r, ltype, d - 1); + if (hafenowner) { + if (hafenowner->faction != u->faction) { + int abgezogenhafen = price / 10; + hafencollected += abgezogenhafen; + price -= abgezogenhafen; + money -= abgezogenhafen; + } + } + if (maxb) { + if (maxowner->faction != u->faction) { + int abgezogensteuer = price * tax_per_size[maxeffsize] / 100; + taxcollected += abgezogensteuer; + price -= abgezogensteuer; + money -= abgezogensteuer; + } + } + u->n += price; + change_money(u, price); + fset(u, UFL_LONGACTION | UFL_NOTMOVING); + + /* r->money -= price; --- dies wird eben nicht ausgef�hrt, denn die + * Produkte k�nnen auch als Steuern eingetrieben werden. In der Region + * wurden Silberst�cke gegen Luxusg�ter des selben Wertes eingetauscht! + * Falls mehr als max_products Kunden ein Produkt gekauft haben, sinkt + * die Nachfrage f�r das Produkt um 1. Der Z�hler wird wieder auf 0 + * gesetzt. */ + + if (++counter[i] > max_products) { + int d = r_demand(r, ltype); + if (d > 1) { + r_setdemand(r, ltype, d - 1); + } + counter[i] = 0; } - counter[i] = 0; } - } - if (use > 0) { - use_pooled(g_requests[j].unit, ltype->itype->rtype, GET_DEFAULT, use); + if (use > 0) { + use_pooled(g_requests[j]->unit, ltype->itype->rtype, GET_DEFAULT, use); + } } } free(g_requests); @@ -1871,13 +1863,13 @@ static void expandselling(region * r, request * sellorders, int limit) } } -static bool sell(unit * u, request ** sellorders, struct order *ord) +static bool sell(unit * u, econ_request ** sellorders, struct order *ord) { char token[128]; bool unlimited = true; const item_type *itype; const luxury_type *ltype; - int n; + int n, i; region *r = u->region; const char *s; keyword_t kwd; @@ -1896,7 +1888,7 @@ static bool sell(unit * u, request ** sellorders, struct order *ord) /* sellorders sind KEIN array, weil f�r alle items DIE SELBE resource * (das geld der region) aufgebraucht wird. */ - kwd = init_order(ord); + kwd = init_order_depr(ord); assert(kwd == K_SELL); s = gettoken(token, sizeof(token)); @@ -1949,7 +1941,8 @@ static bool sell(unit * u, request ** sellorders, struct order *ord) /* Ein H�ndler kann nur 10 G�ter pro Talentpunkt verkaufen. */ - n = MIN(n, u->number * 10 * effskill(u, SK_TRADE, 0)); + i = u->number * 10 * effskill(u, SK_TRADE, 0); + if (n > i) n = i; if (!n) { cmistake(u, ord, 54, MSG_COMMERCE); @@ -1964,7 +1957,7 @@ static bool sell(unit * u, request ** sellorders, struct order *ord) } else { attrib *a; - request *o; + econ_request *o; int k, available; if (!r_demand(r, ltype)) { @@ -1976,20 +1969,21 @@ static bool sell(unit * u, request ** sellorders, struct order *ord) /* Wenn andere Einheiten das selbe verkaufen, mu� ihr Zeug abgezogen * werden damit es nicht zweimal verkauft wird: */ for (o = *sellorders; o; o = o->next) { - if (o->type.ltype == ltype && o->unit->faction == u->faction) { + if (o->type.trade.ltype == ltype && o->unit->faction == u->faction) { int fpool = o->qty - get_pooled(o->unit, itype->rtype, GET_RESERVE, INT_MAX); - available -= MAX(0, fpool); + if (fpool < 0) fpool = 0; + available -= fpool; } } - n = MIN(n, available); + if (n > available) n = available; if (n <= 0) { cmistake(u, ord, 264, MSG_COMMERCE); return false; } - /* Hier wird request->type verwendet, weil die obere limit durch + /* Hier wird production->type verwendet, weil die obere limit durch * das silber gegeben wird (region->money), welches f�r alle * (!) produkte als summe gilt, als nicht wie bei der * produktion, wo f�r jedes produkt einzeln eine obere limite @@ -2008,62 +2002,20 @@ static bool sell(unit * u, request ** sellorders, struct order *ord) k -= a->data.i; } - n = MIN(n, k); + if (n > k) n = k; assert(n >= 0); /* die Menge der verkauften G�ter merken */ a->data.i += n; - o = (request *)calloc(1, sizeof(request)); + o = (econ_request *)calloc(1, sizeof(econ_request)); o->unit = u; o->qty = n; - o->type.ltype = ltype; + o->type.trade.ltype = ltype; addlist(sellorders, o); return unlimited; } } -/* ------------------------------------------------------------- */ - -static void expandstealing(region * r, request * stealorders) -{ - const resource_type *rsilver = get_resourcetype(R_SILVER); - unsigned int j; - - assert(rsilver); - - expandorders(r, stealorders); - if (!norders) return; - - /* F�r jede unit in der Region wird Geld geklaut, wenn sie Opfer eines - * Beklauen-Orders ist. Jedes Opfer mu� einzeln behandelt werden. - * - * u ist die beklaute unit. oa.unit ist die klauende unit. - */ - - for (j = 0; j != norders && g_requests[j].unit->n <= g_requests[j].unit->wants; j++) { - unit *u = findunitg(g_requests[j].no, r); - int n = 0; - if (u && u->region == r) { - n = get_pooled(u, rsilver, GET_ALL, INT_MAX); - } - if (n > 10 && rplane(r) && (rplane(r)->flags & PFL_NOALLIANCES)) { - /* In Questen nur reduziertes Klauen */ - n = 10; - } - if (n > 0) { - n = MIN(n, g_requests[j].unit->wants); - use_pooled(u, rsilver, GET_ALL, n); - g_requests[j].unit->n = n; - change_money(g_requests[j].unit, n); - ADDMSG(&u->faction->msgs, msg_message("stealeffect", "unit region amount", - u, u->region, n)); - } - add_income(g_requests[j].unit, IC_STEAL, g_requests[j].unit->wants, g_requests[j].unit->n); - fset(g_requests[j].unit, UFL_LONGACTION | UFL_NOTMOVING); - } - free(g_requests); -} - /* ------------------------------------------------------------- */ static void plant(unit * u, int raw) { @@ -2105,8 +2057,9 @@ static void plant(unit * u, int raw) return; } - n = MIN(skill * u->number, n); - n = MIN(raw, n); + i = skill * u->number; + if (i > raw) i = raw; + if (n > i) n = i; /* F�r jedes Kraut Talent*10% Erfolgschance. */ for (i = n; i > 0; i--) { if (rng_int() % 10 < skill) @@ -2117,7 +2070,7 @@ static void plant(unit * u, int raw) /* Alles ok. Abziehen. */ use_pooled(u, rt_water, GET_DEFAULT, 1); use_pooled(u, itype->rtype, GET_DEFAULT, n); - rsetherbs(r, (short)(rherbs(r) + planted)); + rsetherbs(r, rherbs(r) + planted); ADDMSG(&u->faction->msgs, msg_message("plant", "unit region amount herb", u, r, planted, itype->rtype)); } @@ -2151,14 +2104,14 @@ static void planttrees(unit * u, int raw) } /* wenn eine Anzahl angegeben wurde, nur soviel verbrauchen */ - raw = MIN(raw, skill * u->number); + if (raw > skill * u->number) raw = skill * u->number; n = get_pooled(u, rtype, GET_DEFAULT, raw); if (n == 0) { ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "resource_missing", "missing", rtype)); return; } - n = MIN(raw, n); + if (n > raw) n = raw; /* F�r jeden Samen Talent*10% Erfolgschance. */ for (i = n; i > 0; i--) { @@ -2208,7 +2161,8 @@ static void breedtrees(unit * u, int raw) } /* wenn eine Anzahl angegeben wurde, nur soviel verbrauchen */ - raw = MIN(skill * u->number, raw); + i = skill * u->number; + if (raw > i) raw = i; n = get_pooled(u, rtype, GET_DEFAULT, raw); /* Samen pr�fen */ if (n == 0) { @@ -2216,7 +2170,7 @@ static void breedtrees(unit * u, int raw) msg_feedback(u, u->thisorder, "resource_missing", "missing", rtype)); return; } - n = MIN(raw, n); + if (n > raw) n = raw; /* F�r jeden Samen Talent*5% Erfolgschance. */ for (i = n; i > 0; i--) { @@ -2258,7 +2212,7 @@ static void breedhorses(unit * u) } effsk = effskill(u, SK_HORSE_TRAINING, 0); n = u->number * effsk; - n = MIN(n, horses); + if (n > horses) n = horses; for (c = 0; c < n; c++) { if (rng_int() % 100 < effsk) { @@ -2287,7 +2241,7 @@ static void breed_cmd(unit * u, struct order *ord) } /* z�chte [] */ - (void)init_order(ord); + (void)init_order_depr(ord); s = gettoken(token, sizeof(token)); m = s ? atoip(s) : 0; @@ -2354,7 +2308,7 @@ static void research_cmd(unit * u, struct order *ord) region *r = u->region; keyword_t kwd; - kwd = init_order(ord); + kwd = init_order_depr(ord); assert(kwd == K_RESEARCH); if (effskill(u, SK_HERBALISM, 0) < 7) { @@ -2383,162 +2337,11 @@ static void research_cmd(unit * u, struct order *ord) } } -static int max_skill(region * r, faction * f, skill_t sk) -{ - unit *u; - int w = 0; - - for (u = r->units; u; u = u->next) { - if (u->faction == f) { - int effsk = effskill(u, sk, 0); - if (effsk > w) { - w = effsk; - } - } - } - - return w; -} - -message * check_steal(const unit * u, struct order *ord) { - plane *pl; - - if (fval(u_race(u), RCF_NOSTEAL)) { - return msg_feedback(u, ord, "race_nosteal", "race", u_race(u)); - } - - if (fval(u->region->terrain, SEA_REGION) && u_race(u) != get_race(RC_AQUARIAN)) { - return msg_feedback(u, ord, "error_onlandonly", ""); - } - - pl = rplane(u->region); - if (pl && fval(pl, PFL_NOATTACK)) { - return msg_feedback(u, ord, "error270", ""); - } - return 0; -} - -static void steal_cmd(unit * u, struct order *ord, request ** stealorders) -{ - const resource_type *rring = get_resourcetype(R_RING_OF_NIMBLEFINGER); - int n, i, id, effsk; - bool goblin = false; - request *o; - unit *u2 = NULL; - region *r = u->region; - faction *f = NULL; - message * msg; - keyword_t kwd; - - kwd = init_order(ord); - assert(kwd == K_STEAL); - - assert(skill_enabled(SK_PERCEPTION) && skill_enabled(SK_STEALTH)); - - msg = check_steal(u, ord); - if (msg) { - ADDMSG(&u->faction->msgs, msg); - return; - } - id = read_unitid(u->faction, r); - if (id > 0) { - u2 = findunitr(r, id); - } - if (u2 && u2->region == u->region) { - f = u2->faction; - } - else { - /* TODO: is this really necessary? it's the only time we use faction.c/deadhash - * it allows stealing from a unit in a dead faction, but why? */ - f = dfindhash(id); - } - - for (u2 = r->units; u2; u2 = u2->next) { - if (u2->faction == f && cansee(u->faction, r, u2, 0)) - break; - } - - if (!u2) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", - "")); - return; - } - - if (IsImmune(u2->faction)) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "newbie_immunity_error", "turns", NewbieImmunity())); - return; - } - - if (u->faction->alliance && u->faction->alliance == u2->faction->alliance) { - cmistake(u, ord, 47, MSG_INCOME); - return; - } - - assert(u->region == u2->region); - if (!can_contact(r, u, u2)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error60", "")); - return; - } - - effsk = effskill(u, SK_STEALTH, 0); - n = effsk - max_skill(r, f, SK_PERCEPTION); - - if (n <= 0) { - /* Wahrnehmung == Tarnung */ - if (u_race(u) != get_race(RC_GOBLIN) || effsk <= 3) { - ADDMSG(&u->faction->msgs, msg_message("stealfail", "unit target", u, u2)); - if (n == 0) { - ADDMSG(&u2->faction->msgs, msg_message("stealdetect", "unit", u2)); - } - else { - ADDMSG(&u2->faction->msgs, msg_message("thiefdiscover", "unit target", - u, u2)); - } - return; - } - else { - ADDMSG(&u->faction->msgs, msg_message("stealfatal", "unit target", u, - u2)); - ADDMSG(&u2->faction->msgs, msg_message("thiefdiscover", "unit target", u, - u2)); - n = 1; - goblin = true; - } - } - - i = MIN(u->number, i_get(u->items, rring->itype)); - if (i > 0) { - n *= STEALINCOME * (u->number + i * (roqf_factor() - 1)); - } - else { - n *= u->number * STEALINCOME; - } - - u->wants = n; - - /* wer dank unsichtbarkeitsringen klauen kann, muss nicht unbedingt ein - * guter dieb sein, schliesslich macht man immer noch sehr viel laerm */ - - o = (request *)calloc(1, sizeof(request)); - o->unit = u; - o->qty = 1; /* Betrag steht in u->wants */ - o->no = u2->no; - o->type.goblin = goblin; /* Merken, wenn Goblin-Spezialklau */ - addlist(stealorders, o); - - /* Nur soviel PRODUCEEXP wie auch tatsaechlich gemacht wurde */ - - produceexp(u, SK_STEALTH, MIN(n, u->number)); -} - -/* ------------------------------------------------------------- */ - static void expandentertainment(region * r) { unit *u; int m = entertainmoney(r); - request *o; + econ_request *o; for (o = &entertainers[0]; o != nextentertainer; ++o) { double part = m / (double)entertaining; @@ -2553,7 +2356,7 @@ static void expandentertainment(region * r) entertaining -= o->qty; /* Nur soviel PRODUCEEXP wie auch tats�chlich gemacht wurde */ - produceexp(u, SK_ENTERTAINMENT, MIN(u->n, u->number)); + produceexp(u, SK_ENTERTAINMENT, (u->n < u->number) ? u->n : u->number); add_income(u, IC_ENTERTAIN, o->qty, u->n); fset(u, UFL_LONGACTION | UFL_NOTMOVING); } @@ -2563,12 +2366,12 @@ void entertain_cmd(unit * u, struct order *ord) { region *r = u->region; int max_e; - request *o; + econ_request *o; static int entertainbase = 0; static int entertainperlevel = 0; keyword_t kwd; - kwd = init_order(ord); + kwd = init_order_depr(ord); assert(kwd == K_ENTERTAIN); if (!entertainbase) { const char *str = config_get("entertain.base"); @@ -2604,7 +2407,7 @@ void entertain_cmd(unit * u, struct order *ord) max_e = getuint(); if (max_e != 0) { - u->wants = MIN(u->wants, max_e); + if (u->wants > max_e) u->wants = max_e; } o = nextentertainer++; o->unit = u; @@ -2616,7 +2419,7 @@ void entertain_cmd(unit * u, struct order *ord) * \return number of working spaces taken by players */ static void -expandwork(region * r, request * work_begin, request * work_end, int maxwork) +expandwork(region * r, econ_request * work_begin, econ_request * work_end, int maxwork) { int earnings; /* n: verbleibende Einnahmen */ @@ -2624,7 +2427,7 @@ expandwork(region * r, request * work_begin, request * work_end, int maxwork) int jobs = maxwork; int p_wage = wage(r, NULL, NULL, turn); int money = rmoney(r); - request *o; + econ_request *o; for (o = work_begin; o != work_end; ++o) { unit *u = o->unit; @@ -2636,9 +2439,9 @@ expandwork(region * r, request * work_begin, request * work_end, int maxwork) if (jobs >= working) workers = u->number; else { - int r = (u->number * jobs) % working; + int req = (u->number * jobs) % working; workers = u->number * jobs / working; - if (r > 0 && rng_int() % working < r) + if (req > 0 && rng_int() % working < req) workers++; } @@ -2667,7 +2470,7 @@ expandwork(region * r, request * work_begin, request * work_end, int maxwork) rsetmoney(r, money + earnings); } -static int do_work(unit * u, order * ord, request * o) +static int do_work(unit * u, order * ord, econ_request * o) { if (playerrace(u_race(u))) { region *r = u->region; @@ -2702,74 +2505,74 @@ static int do_work(unit * u, order * ord, request * o) return -1; } -static void expandloot(region * r, request * lootorders) +static void expandloot(region * r, econ_request * lootorders) { - unit *u; - unsigned int i; - int m, looted = 0; - int startmoney = rmoney(r); - - expandorders(r, lootorders); - if (!norders) - return; + unsigned int norders; - for (i = 0; i != norders && startmoney > looted + TAXFRACTION * 2; i++) { - change_money(g_requests[i].unit, TAXFRACTION); - g_requests[i].unit->n += TAXFRACTION; - /*Looting destroys double the money*/ - looted += TAXFRACTION * 2; - } - rsetmoney(r, startmoney - looted); - free(g_requests); + norders = expandorders(r, lootorders); + if (norders > 0) { + unit *u; + unsigned int i; + int m, looted = 0; + int startmoney = rmoney(r); + + for (i = 0; i != norders && startmoney > looted + TAXFRACTION * 2; i++) { + change_money(g_requests[i]->unit, TAXFRACTION); + g_requests[i]->unit->n += TAXFRACTION; + /*Looting destroys double the money*/ + looted += TAXFRACTION * 2; + } + rsetmoney(r, startmoney - looted); + free(g_requests); - /* Lowering morale by 1 depending on the looted money (+20%) */ - m = region_get_morale(r); - if (m && startmoney>0) { - if (rng_int() % 100 < 20 + (looted * 80) / startmoney) { - /*Nur Moral -1, turns is not changed, so the first time nothing happens if the morale is good*/ - region_set_morale(r, m - 1, -1); + /* Lowering morale by 1 depending on the looted money (+20%) */ + m = region_get_morale(r); + if (m && startmoney > 0) { + if (rng_int() % 100 < 20 + (looted * 80) / startmoney) { + /*Nur Moral -1, turns is not changed, so the first time nothing happens if the morale is good*/ + region_set_morale(r, m - 1, -1); + } } - } - - for (u = r->units; u; u = u->next) { - if (u->n >= 0) { - add_income(u, IC_LOOT, u->wants, u->n); - fset(u, UFL_LONGACTION | UFL_NOTMOVING); + for (u = r->units; u; u = u->next) { + if (u->n >= 0) { + add_income(u, IC_LOOT, u->wants, u->n); + fset(u, UFL_LONGACTION | UFL_NOTMOVING); + } } } } -void expandtax(region * r, request * taxorders) +void expandtax(region * r, econ_request * taxorders) { unit *u; - unsigned int i; + unsigned int norders; - expandorders(r, taxorders); - if (!norders) - return; - - for (i = 0; i != norders && rmoney(r) > TAXFRACTION; i++) { - change_money(g_requests[i].unit, TAXFRACTION); - g_requests[i].unit->n += TAXFRACTION; - rsetmoney(r, rmoney(r) - TAXFRACTION); - } - free(g_requests); + norders = expandorders(r, taxorders); + if (norders > 0) { + unsigned int i; + for (i = 0; i != norders && rmoney(r) > TAXFRACTION; i++) { + change_money(g_requests[i]->unit, TAXFRACTION); + g_requests[i]->unit->n += TAXFRACTION; + rsetmoney(r, rmoney(r) - TAXFRACTION); + } + free(g_requests); - for (u = r->units; u; u = u->next) { - if (u->n >= 0) { - add_income(u, IC_TAX, u->wants, u->n); - fset(u, UFL_LONGACTION | UFL_NOTMOVING); + for (u = r->units; u; u = u->next) { + if (u->n >= 0) { + add_income(u, IC_TAX, u->wants, u->n); + fset(u, UFL_LONGACTION | UFL_NOTMOVING); + } } } } -void tax_cmd(unit * u, struct order *ord, request ** taxorders) +void tax_cmd(unit * u, struct order *ord, econ_request ** taxorders) { /* Steuern werden noch vor der Forschung eingetrieben */ region *r = u->region; unit *u2; int n; - request *o; + econ_request *o; int max; keyword_t kwd; static int taxperlevel = 0; @@ -2778,7 +2581,7 @@ void tax_cmd(unit * u, struct order *ord, request ** taxorders) taxperlevel = config_get_int("taxing.perlevel", 0); } - kwd = init_order(ord); + kwd = init_order_depr(ord); assert(kwd == K_TAX); if (!humanoidrace(u_race(u)) && !is_monsters(u->faction)) { @@ -2814,11 +2617,12 @@ void tax_cmd(unit * u, struct order *ord, request ** taxorders) max = INT_MAX; } if (!playerrace(u_race(u))) { - u->wants = MIN(income(u), max); + u->wants = income(u); } else { - u->wants = MIN(n * effskill(u, SK_TAXING, 0) * taxperlevel, max); + u->wants = n * effskill(u, SK_TAXING, 0) * taxperlevel; } + if (u->wants > max) u->wants = max; u2 = is_guarded(r, u); if (u2) { @@ -2831,23 +2635,23 @@ void tax_cmd(unit * u, struct order *ord, request ** taxorders) * fraktionen werden dann bei eintreiben unter allen eintreibenden * einheiten aufgeteilt. */ - o = (request *)calloc(1, sizeof(request)); + o = (econ_request *)calloc(1, sizeof(econ_request)); o->qty = u->wants / TAXFRACTION; o->unit = u; addlist(taxorders, o); return; } -void loot_cmd(unit * u, struct order *ord, request ** lootorders) +void loot_cmd(unit * u, struct order *ord, econ_request ** lootorders) { region *r = u->region; unit *u2; int n; int max; - request *o; + econ_request *o; keyword_t kwd; - kwd = init_order(ord); + kwd = init_order_depr(ord); assert(kwd == K_LOOT); if (config_get_int("rules.enable_loot", 0) == 0 && !is_monsters(u->faction)) { @@ -2888,15 +2692,19 @@ void loot_cmd(unit * u, struct order *ord, request ** lootorders) max = INT_MAX; } if (!playerrace(u_race(u))) { - u->wants = MIN(income(u), max); + u->wants = income(u); + if (u->wants > max) u->wants = max; } else { /* For player start with 20 Silver +10 every 5 level of close combat skill*/ - int skbonus = (MAX(effskill(u, SK_MELEE, 0), effskill(u, SK_SPEAR, 0)) * 2 / 10) + 2; - u->wants = MIN(n * skbonus * 10, max); + int skm = effskill(u, SK_MELEE, 0); + int sks = effskill(u, SK_SPEAR, 0); + int skbonus = ((skm > sks ? skm : sks) * 2 / 10) + 2; + u->wants = n * skbonus * 10; + if (u->wants > max) u->wants = max; } - o = (request *)calloc(1, sizeof(request)); + o = (econ_request *)calloc(1, sizeof(econ_request)); o->qty = u->wants / TAXFRACTION; o->unit = u; addlist(lootorders, o); @@ -2907,8 +2715,8 @@ void loot_cmd(unit * u, struct order *ord, request ** lootorders) #define MAX_WORKERS 2048 void auto_work(region * r) { - request workers[MAX_WORKERS]; - request *nextworker = workers; + econ_request workers[MAX_WORKERS]; + econ_request *nextworker = workers; unit *u; for (u = r->units; u; u = u->next) { @@ -2976,16 +2784,16 @@ static bool rule_autowork(void) { void produce(struct region *r) { - request workers[MAX_WORKERS]; - request *taxorders, *lootorders, *sellorders, *stealorders, *buyorders; + econ_request workers[MAX_WORKERS]; + econ_request *taxorders, *lootorders, *sellorders, *stealorders, *buyorders; unit *u; bool limited = true; - request *nextworker = workers; + econ_request *nextworker = workers; static int bt_cache; static const struct building_type *caravan_bt; static int rc_cache; static const race *rc_insect, *rc_aquarian; - + if (bt_changed(&bt_cache)) { caravan_bt = bt_find("caravan"); } @@ -3127,18 +2935,23 @@ void produce(struct region *r) if (!rule_autowork()) { expandwork(r, workers, nextworker, region_maxworkers(r)); } - if (taxorders) + if (taxorders) { expandtax(r, taxorders); + free_requests(taxorders); + } - if (lootorders) + if (lootorders) { expandloot(r, lootorders); - + free_requests(lootorders); + } /* An erster Stelle Kaufen (expandbuying), die Bauern so Geld bekommen, um * nachher zu beim Verkaufen (expandselling) den Spielern abkaufen zu * k�nnen. */ - if (buyorders) + if (buyorders) { expandbuying(r, buyorders); + free_requests(buyorders); + } if (sellorders) { int limit = rpeasants(r) / TRADE_FRACTION; @@ -3146,13 +2959,16 @@ void produce(struct region *r) && buildingtype_exists(r, caravan_bt, true)) limit *= 2; expandselling(r, sellorders, limited ? limit : INT_MAX); + free_requests(sellorders); } /* Die Spieler sollen alles Geld verdienen, bevor sie beklaut werden * (expandstealing). */ - if (stealorders) + if (stealorders) { expandstealing(r, stealorders); + free_requests(stealorders); + } assert(rmoney(r) >= 0); assert(rpeasants(r) >= 0); diff --git a/src/economy.h b/src/economy.h index 7b0eed8c9..ec12ae0ca 100644 --- a/src/economy.h +++ b/src/economy.h @@ -45,7 +45,24 @@ extern "C" { struct faction; struct order; struct message; - struct request; + + typedef struct econ_request { + struct econ_request *next; + struct unit *unit; + int qty; + union { + struct { + struct order *ord; + } recruit; + struct { + int no; + bool goblin; /* stealing */ + } steal; + struct { + const struct luxury_type *ltype; /* trading */ + } trade; + } type; + } econ_request; int income(const struct unit *u); int entertainmoney(const struct region *r); @@ -54,17 +71,26 @@ extern "C" { void produce(struct region *r); void auto_work(struct region *r); - enum { IC_WORK, IC_ENTERTAIN, IC_TAX, IC_TRADE, IC_TRADETAX, IC_STEAL, IC_MAGIC, IC_LOOT }; + unsigned int expand_production(struct region * r, struct econ_request * requests, struct econ_request ***results); + + typedef enum income_t { IC_WORK, IC_ENTERTAIN, IC_TAX, IC_TRADE, IC_TRADETAX, IC_STEAL, IC_MAGIC, IC_LOOT } income_t; + void add_income(struct unit * u, income_t type, int want, int qty); + void maintain_buildings(struct region *r); void make_item(struct unit * u, const struct item_type * itype, int want); int make_cmd(struct unit *u, struct order *ord); void split_allocations(struct region *r); int give_control_cmd(struct unit *u, struct order *ord); void give_control(struct unit * u, struct unit * u2); - void tax_cmd(struct unit * u, struct order *ord, struct request ** taxorders); - void expandtax(struct region * r, struct request * taxorders); + + void tax_cmd(struct unit * u, struct order *ord, struct econ_request ** taxorders); + void expandtax(struct region * r, struct econ_request * taxorders); + + struct message * steal_message(const struct unit * u, struct order *ord); + void steal_cmd(struct unit * u, struct order *ord, struct econ_request ** stealorders); + void expandstealing(struct region * r, struct econ_request * stealorders); + void add_recruits(struct unit * u, int number, int wanted); - struct message * check_steal(const struct unit * u, struct order *ord); #ifdef __cplusplus } diff --git a/src/economy.test.c b/src/economy.test.c index 83c103f7f..d4322fef7 100644 --- a/src/economy.test.c +++ b/src/economy.test.c @@ -1,4 +1,6 @@ +#ifdef _MSC_VER #include +#endif #include #include "economy.h" @@ -14,10 +16,12 @@ #include #include #include +#include #include #include #include +#include #include #include @@ -30,10 +34,10 @@ static void test_give_control_building(CuTest * tc) struct faction *f; region *r; - test_cleanup(); - f = test_create_faction(0); - r = test_create_region(0, 0, 0); - b = test_create_building(r, 0); + test_setup(); + f = test_create_faction(NULL); + r = test_create_region(0, 0, NULL); + b = test_create_building(r, NULL); u1 = test_create_unit(f, r); u_set_building(u1, b); u2 = test_create_unit(f, r); @@ -41,7 +45,7 @@ static void test_give_control_building(CuTest * tc) CuAssertPtrEquals(tc, u1, building_owner(b)); give_control(u1, u2); CuAssertPtrEquals(tc, u2, building_owner(b)); - test_cleanup(); + test_teardown(); } static void test_give_control_ship(CuTest * tc) @@ -51,10 +55,10 @@ static void test_give_control_ship(CuTest * tc) struct faction *f; region *r; - test_cleanup(); - f = test_create_faction(0); - r = test_create_region(0, 0, 0); - sh = test_create_ship(r, 0); + test_setup(); + f = test_create_faction(NULL); + r = test_create_region(0, 0, NULL); + sh = test_create_ship(r, NULL); u1 = test_create_unit(f, r); u_set_ship(u1, sh); u2 = test_create_unit(f, r); @@ -62,7 +66,7 @@ static void test_give_control_ship(CuTest * tc) CuAssertPtrEquals(tc, u1, ship_owner(sh)); give_control(u1, u2); CuAssertPtrEquals(tc, u2, ship_owner(sh)); - test_cleanup(); + test_teardown(); } struct steal { @@ -82,13 +86,13 @@ static void test_steal_okay(CuTest * tc) { race *rc; struct terrain_type *ter; - test_cleanup(); + test_setup(); ter = test_create_terrain("plain", LAND_REGION); rc = test_create_race("human"); rc->flags = 0; setup_steal(&env, ter, rc); - CuAssertPtrEquals(tc, 0, check_steal(env.u, 0)); - test_cleanup(); + CuAssertPtrEquals(tc, 0, steal_message(env.u, 0)); + test_teardown(); } static void test_steal_nosteal(CuTest * tc) { @@ -97,14 +101,14 @@ static void test_steal_nosteal(CuTest * tc) { terrain_type *ter; message *msg; - test_cleanup(); + test_setup(); ter = test_create_terrain("plain", LAND_REGION); rc = test_create_race("human"); rc->flags = RCF_NOSTEAL; setup_steal(&env, ter, rc); - CuAssertPtrNotNull(tc, msg = check_steal(env.u, 0)); + CuAssertPtrNotNull(tc, msg = steal_message(env.u, 0)); msg_release(msg); - test_cleanup(); + test_teardown(); } static void test_steal_ocean(CuTest * tc) { @@ -113,13 +117,13 @@ static void test_steal_ocean(CuTest * tc) { terrain_type *ter; message *msg; - test_cleanup(); + test_setup(); ter = test_create_terrain("ocean", SEA_REGION); rc = test_create_race("human"); setup_steal(&env, ter, rc); - CuAssertPtrNotNull(tc, msg = check_steal(env.u, 0)); + CuAssertPtrNotNull(tc, msg = steal_message(env.u, 0)); msg_release(msg); - test_cleanup(); + test_teardown(); } static struct unit *create_recruiter(void) { @@ -137,11 +141,19 @@ static struct unit *create_recruiter(void) { return u; } +static void setup_production(void) { + init_resources(); + mt_register(mt_new_va("produce", "unit:unit", "region:region", "amount:int", "wanted:int", "resource:resource", NULL)); + mt_register(mt_new_va("income", "unit:unit", "region:region", "amount:int", "wanted:int", "mode:int", NULL)); + mt_register(mt_new_va("buy", "unit:unit", "money:int", NULL)); + mt_register(mt_new_va("buyamount", "unit:unit", "amount:int", "resource:resource", NULL)); +} + static void test_heroes_dont_recruit(CuTest * tc) { unit *u; test_setup(); - init_resources(); + setup_production(); u = create_recruiter(); fset(u, UFL_HERO); @@ -152,14 +164,14 @@ static void test_heroes_dont_recruit(CuTest * tc) { CuAssertIntEquals(tc, 1, u->number); CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "error_herorecruit")); - test_cleanup(); + test_teardown(); } static void test_normals_recruit(CuTest * tc) { unit *u; test_setup(); - init_resources(); + setup_production(); u = create_recruiter(); unit_addorder(u, create_order(K_RECRUIT, default_locale, "1")); @@ -167,32 +179,158 @@ static void test_normals_recruit(CuTest * tc) { CuAssertIntEquals(tc, 2, u->number); - test_cleanup(); + test_teardown(); +} + +/** + * Create any terrain types that are used by the trade rules. + * + * This should prevent newterrain from returning NULL. + */ +static void setup_terrains(CuTest *tc) { + test_create_terrain("plain", LAND_REGION | FOREST_REGION | WALK_INTO | CAVALRY_REGION | FLY_INTO); + test_create_terrain("ocean", SEA_REGION | SWIM_INTO | FLY_INTO); + test_create_terrain("swamp", LAND_REGION | WALK_INTO | FLY_INTO); + test_create_terrain("desert", LAND_REGION | WALK_INTO | FLY_INTO); + test_create_terrain("mountain", LAND_REGION | WALK_INTO | FLY_INTO); + init_terrains(); + CuAssertPtrNotNull(tc, newterrain(T_MOUNTAIN)); + CuAssertPtrNotNull(tc, newterrain(T_OCEAN)); + CuAssertPtrNotNull(tc, newterrain(T_PLAIN)); + CuAssertPtrNotNull(tc, newterrain(T_SWAMP)); + CuAssertPtrNotNull(tc, newterrain(T_DESERT)); +} + +static region *setup_trade_region(CuTest *tc, const struct terrain_type *terrain) { + region *r; + item_type *it_luxury; + struct locale * lang = default_locale; + + new_luxurytype(it_luxury = test_create_itemtype("balm"), 5); + locale_setstring(lang, it_luxury->rtype->_name, it_luxury->rtype->_name); + CuAssertStrEquals(tc, it_luxury->rtype->_name, LOC(lang, resourcename(it_luxury->rtype, 0))); + + new_luxurytype(it_luxury = test_create_itemtype("jewel"), 5); + locale_setstring(lang, it_luxury->rtype->_name, it_luxury->rtype->_name); + CuAssertStrEquals(tc, it_luxury->rtype->_name, LOC(lang, resourcename(it_luxury->rtype, 0))); + + r = test_create_region(0, 0, terrain); + setluxuries(r, it_luxury->rtype->ltype); + return r; } -typedef struct request { - struct request *next; - struct unit *unit; - struct order *ord; - int qty; - int no; - union { - bool goblin; /* stealing */ - const struct luxury_type *ltype; /* trading */ - } type; -} request; +static unit *setup_trade_unit(CuTest *tc, region *r, const struct race *rc) { + unit *u; + + UNUSED_ARG(tc); + u = test_create_unit(test_create_faction(rc), r); + set_level(u, SK_TRADE, 2); + return u; +} + +static void test_trade_insect(CuTest *tc) { + /* Insekten k�nnen in W�sten und S�mpfen auch ohne Burgen handeln. */ + unit *u; + region *r; + const item_type *it_luxury; + const item_type *it_silver; + + test_setup(); + setup_production(); + test_create_locale(); + setup_terrains(tc); + r = setup_trade_region(tc, get_terrain("swamp")); + init_terrains(); + + it_luxury = r_luxury(r); + CuAssertPtrNotNull(tc, it_luxury); + it_silver = get_resourcetype(R_SILVER)->itype; + + u = setup_trade_unit(tc, r, test_create_race("insect")); + unit_addorder(u, create_order(K_BUY, u->faction->locale, "1 %s", + LOC(u->faction->locale, resourcename(it_luxury->rtype, 0)))); + + set_item(u, it_silver, 10); + CuAssertPtrEquals(tc, r, u->region); + CuAssertPtrEquals(tc, (void *)it_luxury, (void *)r_luxury(u->region)); + produce(u->region); + CuAssertIntEquals(tc, 1, get_item(u, it_luxury)); + CuAssertIntEquals(tc, 5, get_item(u, it_silver)); + + terraform_region(r, get_terrain("swamp")); + test_teardown(); +} + +static void test_buy_cmd(CuTest *tc) { + region * r; + unit *u; + building *b; + const resource_type *rt_silver; + const item_type *it_luxury; + test_setup(); + setup_production(); + test_create_locale(); + setup_terrains(tc); + r = setup_trade_region(tc, test_create_terrain("swamp", LAND_REGION)); + init_terrains(); + + it_luxury = r_luxury(r); + CuAssertPtrNotNull(tc, it_luxury); + rt_silver = get_resourcetype(R_SILVER); + CuAssertPtrNotNull(tc, rt_silver); + CuAssertPtrNotNull(tc, rt_silver->itype); + + u = test_create_unit(test_create_faction(NULL), r); + unit_addorder(u, create_order(K_BUY, u->faction->locale, "1 %s", LOC(u->faction->locale, resourcename(it_luxury->rtype, 0)))); + set_item(u, rt_silver->itype, 1000); + + produce(r); + CuAssertPtrNotNullMsg(tc, "trading requires a castle", test_find_messagetype(u->faction->msgs, "error119")); + test_clear_messages(u->faction); + freset(u, UFL_LONGACTION); + + b = test_create_building(r, test_create_buildingtype("castle")); + produce(r); + CuAssertPtrNotNullMsg(tc, "castle must have size >=2", test_find_messagetype(u->faction->msgs, "error119")); + test_clear_messages(u->faction); + freset(u, UFL_LONGACTION); + + b->size = 2; + produce(r); + CuAssertPtrEquals(tc, NULL, test_find_messagetype(u->faction->msgs, "error119")); + CuAssertPtrNotNullMsg(tc, "traders need SK_TRADE skill", test_find_messagetype(u->faction->msgs, "error102")); + test_clear_messages(u->faction); + freset(u, UFL_LONGACTION); + + /* at last, the happy case: */ + set_level(u, SK_TRADE, 1); + produce(r); + CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "buy")); + CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "buyamount")); + CuAssertIntEquals(tc, 1, get_item(u, it_luxury)); + CuAssertIntEquals(tc, 995, get_item(u, rt_silver->itype)); + test_teardown(); +} + +static void arm_unit(unit *u) { + item_type *it_sword; + + it_sword = test_create_itemtype("sword"); + new_weapontype(it_sword, 0, frac_zero, NULL, 0, 0, 0, SK_MELEE); + i_change(&u->items, it_sword, u->number); + set_level(u, SK_MELEE, 1); +} static void test_tax_cmd(CuTest *tc) { order *ord; faction *f; region *r; unit *u; - item_type *sword, *silver; - request *taxorders = 0; - + item_type *silver; + econ_request *taxorders = 0; test_setup(); - init_resources(); + setup_production(); config_set("taxing.perlevel", "20"); f = test_create_faction(NULL); r = test_create_region(0, 0, NULL); @@ -208,10 +346,7 @@ static void test_tax_cmd(CuTest *tc) { silver = get_resourcetype(R_SILVER)->itype; - sword = test_create_itemtype("sword"); - new_weapontype(sword, 0, frac_zero, NULL, 0, 0, 0, SK_MELEE, 1); - i_change(&u->items, sword, 1); - set_level(u, SK_MELEE, 1); + arm_unit(u); tax_cmd(u, ord, &taxorders); CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "error_no_tax_skill")); @@ -238,7 +373,15 @@ static void test_tax_cmd(CuTest *tc) { test_clear_messages(u->faction); free_order(ord); - test_cleanup(); + test_teardown(); +} + +static void setup_economy(void) { + mt_register(mt_new_va("recruit", "unit:unit", "region:region", "amount:int", "want:int", NULL)); + mt_register(mt_new_va("maintenance", "unit:unit", "building:building", NULL)); + mt_register(mt_new_va("maintenancefail", "unit:unit", "building:building", NULL)); + mt_register(mt_new_va("maintenance_nowork", "building:building", NULL)); + mt_register(mt_new_va("maintenance_noowner", "building:building", NULL)); } /** @@ -253,11 +396,12 @@ static void test_maintain_buildings(CuTest *tc) { maintenance *req; item_type *itype; - test_cleanup(); + test_setup(); + setup_economy(); btype = test_create_buildingtype("Hort"); btype->maxsize = 10; - r = test_create_region(0, 0, 0); - f = test_create_faction(0); + r = test_create_region(0, 0, NULL); + f = test_create_faction(NULL); u = test_create_unit(f, r); b = test_create_building(r, btype); itype = test_create_itemtype("money"); @@ -305,7 +449,7 @@ static void test_maintain_buildings(CuTest *tc) { CuAssertPtrNotNull(tc, test_find_messagetype(r->msgs, "maintenance_noowner")); test_clear_messagelist(&r->msgs); - test_cleanup(); + test_teardown(); } static void test_recruit(CuTest *tc) { @@ -313,8 +457,9 @@ static void test_recruit(CuTest *tc) { faction *f; test_setup(); - f = test_create_faction(0); - u = test_create_unit(f, test_create_region(0, 0, 0)); + setup_economy(); + f = test_create_faction(NULL); + u = test_create_unit(f, test_create_region(0, 0, NULL)); CuAssertIntEquals(tc, 1, u->number); CuAssertIntEquals(tc, 1, f->num_people); CuAssertIntEquals(tc, 1, f->num_units); @@ -329,7 +474,7 @@ static void test_recruit(CuTest *tc) { add_recruits(u, 1, 2); CuAssertIntEquals(tc, 3, u->number); CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "recruit")); - test_cleanup(); + test_teardown(); } static void test_income(CuTest *tc) @@ -338,11 +483,11 @@ static void test_income(CuTest *tc) unit *u; test_setup(); rc = test_create_race("nerd"); - u = test_create_unit(test_create_faction(rc), test_create_region(0, 0, 0)); + u = test_create_unit(test_create_faction(rc), test_create_region(0, 0, NULL)); CuAssertIntEquals(tc, 20, income(u)); u->number = 5; CuAssertIntEquals(tc, 100, income(u)); - test_cleanup(); + test_teardown(); } static void test_modify_material(CuTest *tc) { @@ -352,9 +497,9 @@ static void test_modify_material(CuTest *tc) { resource_mod *mod; test_setup(); - init_resources(); + setup_production(); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); set_level(u, SK_WEAPONSMITH, 1); /* the unit's race gets 2x savings on iron used to produce goods */ @@ -390,7 +535,7 @@ static void test_modify_material(CuTest *tc) { CuAssertIntEquals(tc, 2, get_item(u, itype)); CuAssertIntEquals(tc, 0, get_item(u, rtype->itype)); - test_cleanup(); + test_teardown(); } static void test_modify_skill(CuTest *tc) { @@ -401,9 +546,9 @@ static void test_modify_skill(CuTest *tc) { resource_mod *mod; test_setup(); - init_resources(); + setup_production(); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); set_level(u, SK_WEAPONSMITH, 1); itype = test_create_itemtype("iron"); @@ -448,7 +593,7 @@ static void test_modify_skill(CuTest *tc) { CuAssertIntEquals(tc, 5, get_item(u, itype)); CuAssertIntEquals(tc, 1, get_item(u, rtype->itype)); - test_cleanup(); + test_teardown(); } @@ -460,13 +605,13 @@ static void test_modify_production(CuTest *tc) { double d = 0.6; test_setup(); - init_resources(); + setup_production(); /* make items from other items (turn silver to stone) */ rt_silver = get_resourcetype(R_SILVER); itype = test_create_itemtype("stone"); rtype = itype->rtype; - u = test_create_unit(test_create_faction(0), test_create_region(0,0,0)); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); make_item(u, itype, 1); CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "error_cannotmake")); CuAssertIntEquals(tc, 0, get_item(u, itype)); @@ -550,7 +695,50 @@ static void test_modify_production(CuTest *tc) { split_allocations(u->region); CuAssertIntEquals(tc, 38, get_item(u, itype)); - test_cleanup(); + test_teardown(); +} + +static void test_loot(CuTest *tc) { + unit *u; + faction *f; + item_type *it_silver; + + test_setup(); + setup_production(); + it_silver = test_create_silver(); + config_set("rules.enable_loot", "1"); + u = test_create_unit(f = test_create_faction(NULL), test_create_region(0, 0, NULL)); + u->thisorder = create_order(K_LOOT, f->locale, NULL); + produce(u->region); + CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error48")); /* unit is unarmed */ + test_clear_messages(f); + arm_unit(u); + produce(u->region); + CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "income")); /* unit is unarmed */ + CuAssertIntEquals(tc, 2 * TAXFRACTION, i_get(u->items, it_silver)); + CuAssertIntEquals(tc, UFL_LONGACTION | UFL_NOTMOVING, fval(u, UFL_LONGACTION | UFL_NOTMOVING)); + test_teardown(); +} + +static void test_expand_production(CuTest *tc) { + econ_request *orders; + econ_request **results = NULL; + region *r; + unit *u; + + test_setup(); + orders = calloc(1, sizeof(econ_request)); + orders->qty = 2; + orders->unit = u = test_create_unit(test_create_faction(NULL), r = test_create_region(0, 0, NULL)); + orders->next = NULL; + + u->n = 1; /* will be overwritten */ + CuAssertIntEquals(tc, 2, expand_production(r, orders, &results)); + CuAssertPtrNotNull(tc, results); + CuAssertPtrEquals(tc, u, results[0]->unit); + CuAssertPtrEquals(tc, u, results[1]->unit); + CuAssertIntEquals(tc, 0, u->n); + test_teardown(); } CuSuite *get_economy_suite(void) @@ -568,7 +756,11 @@ CuSuite *get_economy_suite(void) SUITE_ADD_TEST(suite, test_normals_recruit); SUITE_ADD_TEST(suite, test_heroes_dont_recruit); SUITE_ADD_TEST(suite, test_tax_cmd); + SUITE_ADD_TEST(suite, test_buy_cmd); + SUITE_ADD_TEST(suite, test_trade_insect); SUITE_ADD_TEST(suite, test_maintain_buildings); SUITE_ADD_TEST(suite, test_recruit); + SUITE_ADD_TEST(suite, test_loot); + SUITE_ADD_TEST(suite, test_expand_production); return suite; } diff --git a/src/eressea.c b/src/eressea.c old mode 100755 new mode 100644 index 2174450eb..95d190d70 --- a/src/eressea.c +++ b/src/eressea.c @@ -2,23 +2,10 @@ #include "settings.h" #include "eressea.h" -#include "calendar.h" -#include "chaos.h" -#include "items.h" -#include "creport.h" -#include "report.h" -#include "names.h" -#include "reports.h" -#include "spells.h" -#include "vortex.h" -#include "wormhole.h" - #include #include -#if MUSEUM_MODULE #include -#endif #include #include #include @@ -26,7 +13,7 @@ #include #include #include -#include +#include #include #include #include @@ -36,13 +23,29 @@ #include #include +#include "calendar.h" +#include "chaos.h" +#include "items.h" +#include "creport.h" +#include "report.h" +#include "names.h" +#include "reports.h" +#include "spells.h" +#include "vortex.h" +#include "wormhole.h" +#include "xmlreader.h" + +#include +#include + void game_done(void) { +#undef CLEANUP_CODE #ifdef CLEANUP_CODE /* Diese Routine enfernt allen allokierten Speicher wieder. Das ist nur * zum Debugging interessant, wenn man Leak Detection hat, und nach - * nicht freigegebenem Speicher sucht, der nicht bis zum Ende benötigt - * wird (temporäre Hilsstrukturen) */ + * nicht freigegebenem Speicher sucht, der nicht bis zum Ende benoetigt + * wird (temporaere Hilsstrukturen) */ free_game(); @@ -57,10 +60,13 @@ void game_done(void) free_special_directions(); free_locales(); kernel_done(); + dblib_close(); } void game_init(void) { + dblib_open(); + errno = 0; kernel_init(); register_triggers(); register_xmas(); @@ -73,16 +79,12 @@ void game_init(void) register_names(); register_resources(); register_itemfunctions(); -#if MUSEUM_MODULE register_museum(); -#endif wormholes_register(); register_weapons(); register_xerewards(); -#ifdef USE_LIBXML2 register_xmlreader(); -#endif register_attributes(); register_gmcmd(); diff --git a/src/give.c b/src/give.c index da75e56c5..5d5673bd2 100644 --- a/src/give.c +++ b/src/give.c @@ -10,7 +10,9 @@ without prior permission by the authors of Eressea. */ +#ifdef _MSC_VER #include +#endif #include #include "give.h" @@ -43,6 +45,7 @@ #include #include #include +#include #include /* libc includes */ @@ -176,6 +179,7 @@ static void give_horses(unit * s, const item_type * itype, int n) { region *r = s->region; + UNUSED_ARG(itype); if (r->land) { rsethorses(r, rhorses(r) + n); } @@ -185,6 +189,7 @@ static void give_money(unit * s, const item_type * itype, int n) { region *r = s->region; + UNUSED_ARG(itype); if (r->land) { rsetmoney(r, rmoney(r) + n); } @@ -192,14 +197,14 @@ give_money(unit * s, const item_type * itype, int n) int give_item(int want, const item_type * itype, unit * src, unit * dest, -struct order *ord) + struct order *ord) { short error = 0; int n, delta; assert(itype != NULL); n = get_pooled(src, item2resource(itype), GET_SLACK | GET_POOLED_SLACK, want); - n = MIN(want, n); + if (n > want) n = want; delta = n; if (dest && src->faction != dest->faction && src->faction->age < GiveRestriction()) { @@ -239,12 +244,6 @@ struct order *ord) change_reservation(dest, item2resource(itype), r); } #endif -#endif -#if MUSEUM_MODULE && defined(TODO) - /* TODO: use a trigger for the museum warden! */ - if (a_find(dest->attribs, &at_warden)) { - warden_add_give(src, dest, itype, delta); - } #endif } else { @@ -277,6 +276,7 @@ static bool unit_has_cursed_item(const unit * u) } static bool can_give_men(const unit *u, const unit *dst, order *ord, message **msg) { + UNUSED_ARG(dst); if (unit_has_cursed_item(u)) { if (msg) *msg = msg_error(u, ord, 78); } @@ -441,9 +441,8 @@ message * give_men(int n, unit * u, unit * u2, struct order *ord) return msg_error(u, ord, error); } else if (u2->faction != u->faction) { - message *msg = msg_message("give_person", "unit target amount", u, u2, n); - add_message(&u2->faction->msgs, msg); - return msg; + return add_message(&u2->faction->msgs, + msg_message("give_person", "unit target amount", u, u2, n)); } return NULL; } @@ -621,6 +620,79 @@ bool can_give_to(unit *u, unit *u2) { return true; } +static void give_all_items(unit *u, unit *u2, order *ord) { + char token[128]; + const char *s; + + if (!can_give(u, u2, NULL, GIVE_ALLITEMS)) { + feedback_give_not_allowed(u, ord); + return; + } + s = gettoken(token, sizeof(token)); + if (!s || *s == 0) { /* GIVE ALL items that you have */ + + /* do these checks once, not for each item we have: */ + if (u2 && !(u_race(u2)->ec_flags & ECF_GETITEM)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "race_notake", "race", u_race(u2))); + return; + } + + /* für alle items einmal prüfen, ob wir mehr als von diesem Typ + * reserviert ist besitzen und diesen Teil dann übergeben */ + if (u->items) { + item **itmp = &u->items; + while (*itmp) { + item *itm = *itmp; + const item_type *itype = itm->type; + if (itm->number > 0 + && itm->number - get_reservation(u, itype) > 0) { + int n = itm->number - get_reservation(u, itype); + if (give_item(n, itype, u, u2, ord) == 0) { + if (*itmp != itm) + continue; + } + } + itmp = &itm->next; + } + } + } + else { + if (isparam(s, u->faction->locale, P_PERSON)) { + if (!(u_race(u)->ec_flags & ECF_GIVEPERSON)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "race_noregroup", "race", u_race(u))); + } + else { + message * msg; + msg = u2 ? give_men(u->number, u, u2, ord) : disband_men(u->number, u, ord); + if (msg) { + ADDMSG(&u->faction->msgs, msg); + } + } + } + else if (u2 && !(u_race(u2)->ec_flags & ECF_GETITEM)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "race_notake", "race", u_race(u2))); + } + else { + const item_type *itype = finditemtype(s, u->faction->locale); + if (itype != NULL) { + item *i = *i_find(&u->items, itype); + if (i != NULL) { + if (can_give(u, u2, itype, 0)) { + int n = i->number - get_reservation(u, itype); + give_item(n, itype, u, u2, ord); + } + else { + feedback_give_not_allowed(u, ord); + } + } + } + } + } +} + void give_cmd(unit * u, order * ord) { char token[128]; @@ -634,7 +706,7 @@ void give_cmd(unit * u, order * ord) message *msg; keyword_t kwd; - kwd = init_order(ord); + kwd = init_order_depr(ord); assert(kwd == K_GIVE); err = getunit(r, u->faction, &u2); s = gettoken(token, sizeof(token)); @@ -695,8 +767,7 @@ void give_cmd(unit * u, order * ord) item **itmp = &u->items; while (*itmp) { item *itm = *itmp; - const item_type *itype = itm->type; - if (fval(itype, ITF_HERB) && itm->number > 0) { + if (fval(itm->type, ITF_HERB) && itm->number > 0) { /* give_item ändert im fall,das man alles übergibt, die * item-liste der unit, darum continue vor pointerumsetzten */ if (give_item(itm->number, itm->type, u, u2, ord) == 0) { @@ -730,75 +801,7 @@ void give_cmd(unit * u, order * ord) } else if (p == P_ANY) { - const char *s; - - if (!can_give(u, u2, NULL, GIVE_ALLITEMS)) { - feedback_give_not_allowed(u, ord); - return; - } - s = gettoken(token, sizeof(token)); - if (!s || *s == 0) { /* GIVE ALL items that you have */ - - /* do these checks once, not for each item we have: */ - if (u2 && !(u_race(u2)->ec_flags & ECF_GETITEM)) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "race_notake", "race", u_race(u2))); - return; - } - - /* für alle items einmal prüfen, ob wir mehr als von diesem Typ - * reserviert ist besitzen und diesen Teil dann übergeben */ - if (u->items) { - item **itmp = &u->items; - while (*itmp) { - item *itm = *itmp; - const item_type *itype = itm->type; - if (itm->number > 0 - && itm->number - get_reservation(u, itype) > 0) { - n = itm->number - get_reservation(u, itype); - if (give_item(n, itype, u, u2, ord) == 0) { - if (*itmp != itm) - continue; - } - } - itmp = &itm->next; - } - } - } - else { - if (isparam(s, u->faction->locale, P_PERSON)) { - if (!(u_race(u)->ec_flags & ECF_GIVEPERSON)) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "race_noregroup", "race", u_race(u))); - } - else { - message * msg; - msg = u2 ? give_men(u->number, u, u2, ord) : disband_men(u->number, u, ord); - if (msg) { - ADDMSG(&u->faction->msgs, msg); - } - } - } - else if (u2 && !(u_race(u2)->ec_flags & ECF_GETITEM)) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "race_notake", "race", u_race(u2))); - } - else { - itype = finditemtype(s, u->faction->locale); - if (itype != NULL) { - item *i = *i_find(&u->items, itype); - if (i != NULL) { - if (can_give(u, u2, itype, 0)) { - n = i->number - get_reservation(u, itype); - give_item(n, itype, u, u2, ord); - } - else { - feedback_give_not_allowed(u, ord); - } - } - } - } - } + give_all_items(u, u2, ord); return; } else if (p == P_EACH) { @@ -819,13 +822,12 @@ void give_cmd(unit * u, order * ord) } if (isparam(s, u->faction->locale, P_PERSON)) { - message * msg; if (!(u_race(u)->ec_flags & ECF_GIVEPERSON)) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "race_noregroup", "race", u_race(u))); return; } - n = MIN(u->number, n); + if (n > u->number) n = u->number; msg = u2 ? give_men(n, u, u2, ord) : disband_men(n, u, ord); if (msg) { ADDMSG(&u->faction->msgs, msg); diff --git a/src/give.test.c b/src/give.test.c index f38028e10..1f1985b6a 100644 --- a/src/give.test.c +++ b/src/give.test.c @@ -52,13 +52,33 @@ static void setup_give(struct give *env) { init_locale(env->lang); env->f1->locale = env->lang; } + + /* success messages: */ + mt_register(mt_new_va("receive_person", "unit:unit", "target:unit", "amount:int", NULL)); + mt_register(mt_new_va("give_person", "unit:unit", "target:unit", "amount:int", NULL)); + mt_register(mt_new_va("give_person_peasants", "unit:unit", "amount:int", NULL)); + mt_register(mt_new_va("give_person_ocean", "unit:unit", "amount:int", NULL)); + mt_register(mt_new_va("receive", "unit:unit", "target:unit", "resource:resource", "amount:int", NULL)); + mt_register(mt_new_va("give", "unit:unit", "target:unit", "resource:resource", "amount:int", NULL)); + mt_register(mt_new_va("give_peasants", "unit:unit", "resource:resource", "amount:int", NULL)); + /* error messages: */ + mt_register(mt_new_va("too_many_units_in_faction", "unit:unit", "region:region", "command:order", "allowed:int", NULL)); + mt_register(mt_new_va("too_many_units_in_alliance", "unit:unit", "region:region", "command:order", "allowed:int", NULL)); + mt_register(mt_new_va("feedback_no_contact", "unit:unit", "region:region", "command:order", "target:unit", NULL)); + mt_register(mt_new_va("feedback_give_forbidden", "unit:unit", "region:region", "command:order", NULL)); + mt_register(mt_new_va("peasants_give_invalid", "unit:unit", "region:region", "command:order", NULL)); + mt_register(mt_new_va("giverestriction", "unit:unit", "region:region", "command:order", "turns:int", NULL)); + mt_register(mt_new_va("error_unit_size", "unit:unit", "region:region", "command:order", "maxsize:int", NULL)); + mt_register(mt_new_va("nogive_reserved", "unit:unit", "region:region", "command:order", "resource:resource", "reservation:int", NULL)); + mt_register(mt_new_va("race_notake", "unit:unit", "region:region", "command:order", "race:race", NULL)); + mt_register(mt_new_va("race_noregroup", "unit:unit", "region:region", "command:order", "race:race", NULL)); } static void test_give_unit(CuTest * tc) { struct give env = { 0 }; test_setup_ex(tc); - env.f1 = test_create_faction(0); - env.f2 = test_create_faction(0); + env.f1 = test_create_faction(NULL); + env.f2 = test_create_faction(NULL); setup_give(&env); config_set("rules.give.max_men", "0"); give_unit(env.src, env.dst, NULL); @@ -71,14 +91,14 @@ static void test_give_unit(CuTest * tc) { CuAssertPtrEquals(tc, 0, env.f1->units); CuAssertPtrNotNull(tc, test_find_messagetype(env.f1->msgs, "give_person")); CuAssertPtrNotNull(tc, test_find_messagetype(env.f2->msgs, "receive_person")); - test_cleanup(); + test_teardown(); } static void test_give_unit_limits(CuTest * tc) { struct give env = { 0 }; test_setup_ex(tc); - env.f1 = test_create_faction(0); - env.f2 = test_create_faction(0); + env.f1 = test_create_faction(NULL); + env.f2 = test_create_faction(NULL); setup_give(&env); CuAssertIntEquals(tc, 1, env.f1->num_units); CuAssertIntEquals(tc, 1, env.f2->num_units); @@ -89,43 +109,43 @@ static void test_give_unit_limits(CuTest * tc) { CuAssertIntEquals(tc, 1, env.f1->num_units); CuAssertIntEquals(tc, 1, env.f2->num_units); CuAssertPtrNotNull(tc, test_find_messagetype(env.f1->msgs, "too_many_units_in_faction")); - test_cleanup(); + test_teardown(); } static void test_give_unit_to_peasants(CuTest * tc) { struct give env = { 0 }; test_setup_ex(tc); - env.f1 = test_create_faction(0); + env.f1 = test_create_faction(NULL); env.f2 = 0; setup_give(&env); rsetpeasants(env.r, 0); give_unit(env.src, NULL, NULL); CuAssertIntEquals(tc, 0, env.src->number); CuAssertIntEquals(tc, 1, rpeasants(env.r)); - test_cleanup(); + test_teardown(); } static void test_give_unit_to_ocean(CuTest * tc) { struct give env = { 0 }; test_setup_ex(tc); - env.f1 = test_create_faction(0); + env.f1 = test_create_faction(NULL); env.f2 = 0; setup_give(&env); env.r->terrain = test_create_terrain("ocean", SEA_REGION); give_unit(env.src, NULL, NULL); CuAssertIntEquals(tc, 0, env.src->number); - test_cleanup(); + test_teardown(); } static void test_give_men(CuTest * tc) { struct give env = { 0 }; test_setup_ex(tc); - env.f2 = env.f1 = test_create_faction(0); + env.f2 = env.f1 = test_create_faction(NULL); setup_give(&env); CuAssertPtrEquals(tc, 0, give_men(1, env.src, env.dst, NULL)); CuAssertIntEquals(tc, 2, env.dst->number); CuAssertIntEquals(tc, 0, env.src->number); - test_cleanup(); + test_teardown(); } static void test_give_men_magicians(CuTest * tc) { @@ -134,7 +154,7 @@ static void test_give_men_magicians(CuTest * tc) { message * msg; test_setup_ex(tc); - env.f2 = env.f1 = test_create_faction(0); + env.f2 = env.f1 = test_create_faction(NULL); setup_give(&env); set_level(env.src, SK_MAGIC, 1); CuAssertPtrNotNull(tc, msg = give_men(1, env.src, env.dst, NULL)); @@ -145,27 +165,28 @@ static void test_give_men_magicians(CuTest * tc) { p = rpeasants(env.r); CuAssertPtrNotNull(tc, msg = disband_men(1, env.dst, NULL)); - CuAssertStrEquals(tc, "give_person_peasants", (const char *)msg->parameters[0].v); + CuAssertStrEquals(tc, "give_person_peasants", test_get_messagetype(msg)); CuAssertIntEquals(tc, 0, env.dst->number); CuAssertIntEquals(tc, p+1, rpeasants(env.r)); msg_release(msg); - test_cleanup(); + test_teardown(); } static void test_give_men_limit(CuTest * tc) { struct give env = { 0 }; message *msg; + test_setup_ex(tc); - env.f2 = test_create_faction(0); - env.f1 = test_create_faction(0); + env.f2 = test_create_faction(NULL); + env.f1 = test_create_faction(NULL); setup_give(&env); config_set("rules.give.max_men", "1"); /* below the limit, give men, increase newbies counter */ usetcontact(env.dst, env.src); msg = give_men(1, env.src, env.dst, NULL); - CuAssertStrEquals(tc, "give_person", (const char *)msg->parameters[0].v); + CuAssertStrEquals(tc, "give_person", test_get_messagetype(msg)); CuAssertIntEquals(tc, 2, env.dst->number); CuAssertIntEquals(tc, 0, env.src->number); CuAssertIntEquals(tc, 1, env.f2->newbies); @@ -174,13 +195,13 @@ static void test_give_men_limit(CuTest * tc) { /* beyond the limit, do nothing */ usetcontact(env.src, env.dst); msg = give_men(2, env.dst, env.src, NULL); - CuAssertStrEquals(tc, "error129", (const char *)msg->parameters[3].v); + CuAssertStrEquals(tc, "error129", test_get_messagetype(msg)); CuAssertIntEquals(tc, 2, env.dst->number); CuAssertIntEquals(tc, 0, env.src->number); CuAssertIntEquals(tc, 0, env.f1->newbies); msg_release(msg); - test_cleanup(); + test_teardown(); } static void test_give_men_in_ocean(CuTest * tc) { @@ -188,26 +209,41 @@ static void test_give_men_in_ocean(CuTest * tc) { message * msg; test_setup_ex(tc); - env.f1 = test_create_faction(0); + env.f1 = test_create_faction(NULL); env.f2 = 0; setup_give(&env); env.r->terrain = test_create_terrain("ocean", SEA_REGION); msg = disband_men(1, env.src, NULL); - CuAssertStrEquals(tc, "give_person_ocean", (const char *)msg->parameters[0].v); + CuAssertStrEquals(tc, "give_person_ocean", test_get_messagetype(msg)); CuAssertIntEquals(tc, 0, env.src->number); msg_release(msg); - test_cleanup(); + test_teardown(); } static void test_give_men_too_many(CuTest * tc) { struct give env = { 0 }; test_setup_ex(tc); - env.f2 = env.f1 = test_create_faction(0); + env.f2 = env.f1 = test_create_faction(NULL); setup_give(&env); CuAssertPtrEquals(tc, 0, give_men(2, env.src, env.dst, NULL)); CuAssertIntEquals(tc, 2, env.dst->number); CuAssertIntEquals(tc, 0, env.src->number); - test_cleanup(); + test_teardown(); +} + +static void test_give_cmd_limit(CuTest * tc) { + struct give env = { 0 }; + unit *u; + test_setup_ex(tc); + env.f2 = env.f1 = test_create_faction(NULL); + setup_give(&env); + u = env.src; + scale_number(u, 2); + u->thisorder = create_order(K_GIVE, u->faction->locale, "%s 1 PERSON", itoa36(env.dst->no)); + give_cmd(u, u->thisorder); + CuAssertIntEquals(tc, 2, env.dst->number); + CuAssertIntEquals(tc, 1, env.src->number); + test_teardown(); } static void test_give_men_none(CuTest * tc) { @@ -215,14 +251,14 @@ static void test_give_men_none(CuTest * tc) { message * msg; test_setup_ex(tc); - env.f2 = env.f1 = test_create_faction(0); + env.f2 = env.f1 = test_create_faction(NULL); setup_give(&env); msg = give_men(0, env.src, env.dst, NULL); CuAssertStrEquals(tc, "error96", test_get_messagetype(msg)); CuAssertIntEquals(tc, 1, env.dst->number); CuAssertIntEquals(tc, 1, env.src->number); msg_release(msg); - test_cleanup(); + test_teardown(); } static void test_give_men_other_faction(CuTest * tc) { @@ -230,16 +266,16 @@ static void test_give_men_other_faction(CuTest * tc) { message * msg; test_setup_ex(tc); - env.f1 = test_create_faction(0); - env.f2 = test_create_faction(0); + env.f1 = test_create_faction(NULL); + env.f2 = test_create_faction(NULL); setup_give(&env); usetcontact(env.dst, env.src); msg = give_men(1, env.src, env.dst, NULL); - CuAssertStrEquals(tc, "give_person", (const char *)msg->parameters[0].v); + CuAssertStrEquals(tc, "give_person", test_get_messagetype(msg)); CuAssertIntEquals(tc, 2, env.dst->number); CuAssertIntEquals(tc, 0, env.src->number); msg_release(msg); - test_cleanup(); + test_teardown(); } static void test_give_men_requires_contact(CuTest * tc) { @@ -248,8 +284,8 @@ static void test_give_men_requires_contact(CuTest * tc) { order *ord; test_setup_ex(tc); - env.f1 = test_create_faction(0); - env.f2 = test_create_faction(0); + env.f1 = test_create_faction(NULL); + env.f2 = test_create_faction(NULL); setup_give(&env); msg = give_men(1, env.src, env.dst, NULL); CuAssertStrEquals(tc, "feedback_no_contact", test_get_messagetype(msg)); @@ -264,20 +300,20 @@ static void test_give_men_requires_contact(CuTest * tc) { msg_release(msg); free_order(ord); - test_cleanup(); + test_teardown(); } static void test_give_men_not_to_self(CuTest * tc) { struct give env = { 0 }; message * msg; test_setup_ex(tc); - env.f2 = env.f1 = test_create_faction(0); + env.f2 = env.f1 = test_create_faction(NULL); setup_give(&env); msg = give_men(1, env.src, env.src, NULL); CuAssertStrEquals(tc, "error10", test_get_messagetype(msg)); CuAssertIntEquals(tc, 1, env.src->number); msg_release(msg); - test_cleanup(); + test_teardown(); } static void test_give_peasants(CuTest * tc) { @@ -285,34 +321,34 @@ static void test_give_peasants(CuTest * tc) { message * msg; test_setup_ex(tc); - env.f1 = test_create_faction(0); + env.f1 = test_create_faction(NULL); env.f2 = 0; setup_give(&env); rsetpeasants(env.r, 0); msg = disband_men(1, env.src, NULL); - CuAssertStrEquals(tc, "give_person_peasants", (const char*)msg->parameters[0].v); + CuAssertStrEquals(tc, "give_person_peasants", test_get_messagetype(msg)); CuAssertIntEquals(tc, 0, env.src->number); CuAssertIntEquals(tc, 1, rpeasants(env.r)); msg_release(msg); - test_cleanup(); + test_teardown(); } static void test_give(CuTest * tc) { struct give env = { 0 }; test_setup_ex(tc); - env.f2 = env.f1 = test_create_faction(0); + env.f2 = env.f1 = test_create_faction(NULL); setup_give(&env); i_change(&env.src->items, env.itype, 10); - CuAssertIntEquals(tc, 0, give_item(10, env.itype, env.src, env.dst, 0)); + CuAssertIntEquals(tc, 0, give_item(10, env.itype, env.src, env.dst, NULL)); CuAssertIntEquals(tc, 0, i_get(env.src->items, env.itype)); CuAssertIntEquals(tc, 10, i_get(env.dst->items, env.itype)); - CuAssertIntEquals(tc, -1, give_item(10, env.itype, env.src, env.dst, 0)); + CuAssertIntEquals(tc, -1, give_item(10, env.itype, env.src, env.dst, NULL)); CuAssertIntEquals(tc, 0, i_get(env.src->items, env.itype)); CuAssertIntEquals(tc, 10, i_get(env.dst->items, env.itype)); - test_cleanup(); + test_teardown(); } static void test_give_cmd(CuTest * tc) { @@ -321,7 +357,7 @@ static void test_give_cmd(CuTest * tc) { test_setup_ex(tc); env.lang = test_create_locale(); - env.f2 = env.f1 = test_create_faction(0); + env.f2 = env.f1 = test_create_faction(NULL); setup_give(&env); i_change(&env.src->items, env.itype, 10); @@ -333,7 +369,7 @@ static void test_give_cmd(CuTest * tc) { CuAssertIntEquals(tc, 5, i_get(env.dst->items, env.itype)); free_order(ord); - test_cleanup(); + test_teardown(); } static void test_give_herbs(CuTest * tc) { @@ -352,19 +388,19 @@ static void test_give_herbs(CuTest * tc) { CuAssertIntEquals(tc, 0, i_get(env.src->items, env.itype)); CuAssertIntEquals(tc, 10, i_get(env.dst->items, env.itype)); free_order(ord); - test_cleanup(); + test_teardown(); } static void test_give_okay(CuTest * tc) { struct give env = { 0 }; test_setup_ex(tc); - env.f2 = env.f1 = test_create_faction(0); + env.f2 = env.f1 = test_create_faction(NULL); setup_give(&env); config_set("rules.give.flags", "0"); - CuAssertPtrEquals(tc, 0, check_give(env.src, env.dst, 0)); - test_cleanup(); + CuAssertPtrEquals(tc, 0, check_give(env.src, env.dst, NULL)); + test_teardown(); } static void test_give_denied_by_rules(CuTest * tc) { @@ -372,14 +408,14 @@ static void test_give_denied_by_rules(CuTest * tc) { struct message *msg; test_setup_ex(tc); - env.f1 = test_create_faction(0); - env.f2 = test_create_faction(0); + env.f1 = test_create_faction(NULL); + env.f2 = test_create_faction(NULL); setup_give(&env); config_set("rules.give.flags", "0"); - CuAssertPtrNotNull(tc, msg = check_give(env.src, env.dst, 0)); + CuAssertPtrNotNull(tc, msg = check_give(env.src, env.dst, NULL)); msg_release(msg); - test_cleanup(); + test_teardown(); } static void test_give_dead_unit(CuTest * tc) { @@ -387,27 +423,27 @@ static void test_give_dead_unit(CuTest * tc) { struct message *msg; test_setup_ex(tc); - env.f1 = test_create_faction(0); - env.f2 = test_create_faction(0); + env.f1 = test_create_faction(NULL); + env.f2 = test_create_faction(NULL); setup_give(&env); env.dst->number = 0; freset(env.dst, UFL_ISNEW); - CuAssertPtrNotNull(tc, msg = check_give(env.src, env.dst, 0)); + CuAssertPtrNotNull(tc, msg = check_give(env.src, env.dst, NULL)); msg_release(msg); - test_cleanup(); + test_teardown(); } static void test_give_new_unit(CuTest * tc) { struct give env = { 0 }; test_setup_ex(tc); - env.f1 = test_create_faction(0); - env.f2 = test_create_faction(0); + env.f1 = test_create_faction(NULL); + env.f2 = test_create_faction(NULL); setup_give(&env); env.dst->number = 0; fset(env.dst, UFL_ISNEW); - CuAssertPtrEquals(tc, 0, check_give(env.src, env.dst, 0)); - test_cleanup(); + CuAssertPtrEquals(tc, 0, check_give(env.src, env.dst, NULL)); + test_teardown(); } static void test_give_invalid_target(CuTest *tc) { @@ -416,7 +452,7 @@ static void test_give_invalid_target(CuTest *tc) { order *ord; test_setup_ex(tc); - env.f1 = test_create_faction(0); + env.f1 = test_create_faction(NULL); env.f2 = 0; setup_give(&env); @@ -428,7 +464,7 @@ static void test_give_invalid_target(CuTest *tc) { CuAssertIntEquals(tc, 10, i_get(env.src->items, env.itype)); CuAssertPtrNotNull(tc, test_find_messagetype(env.f1->msgs, "feedback_unit_not_found")); free_order(ord); - test_cleanup(); + test_teardown(); } CuSuite *get_give_suite(void) @@ -436,6 +472,7 @@ CuSuite *get_give_suite(void) CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_give); SUITE_ADD_TEST(suite, test_give_cmd); + SUITE_ADD_TEST(suite, test_give_cmd_limit); SUITE_ADD_TEST(suite, test_give_men); SUITE_ADD_TEST(suite, test_give_men_magicians); SUITE_ADD_TEST(suite, test_give_men_limit); diff --git a/src/gmtool.c b/src/gmtool.c index 6806a3056..d74f1e46b 100644 --- a/src/gmtool.c +++ b/src/gmtool.c @@ -8,25 +8,19 @@ * */ +#ifdef _MSC_VER #include +#endif + #include #include #include "gmtool.h" -#include "gmtool_structs.h" -#include "chaos.h" -#include "console.h" -#include "listbox.h" -#include "wormhole.h" -#include "calendar.h" -#include "teleport.h" #include #include -#if MUSEUM_MODULE #include -#endif #include #include @@ -41,18 +35,27 @@ #include #include #include -#include #include #include #include -#include -#include +#include #include +#include +#include +#include #include -#include -#include +#include + +#include "gmtool_structs.h" +#include "chaos.h" +#include "console.h" +#include "listbox.h" +#include "wormhole.h" +#include "calendar.h" +#include "teleport.h" +#include "xmlreader.h" #include #include @@ -60,6 +63,7 @@ #include #include #include +#include #include static int g_quit; @@ -567,7 +571,9 @@ static void terraform_at(coordinate * c, const terrain_type * terrain) if (r == NULL) { r = new_region(nx, ny, c->pl, 0); } - terraform_region(r, terrain); + if (!(r->units && fval(r->terrain, LAND_REGION) && !fval(terrain, LAND_REGION))) { + terraform_region(r, terrain); + } } } @@ -591,7 +597,9 @@ terraform_selection(selection * selected, const terrain_type * terrain) if (r == NULL) { r = new_region(nx, ny, pl, 0); } - terraform_region(r, terrain); + if (!(r->units && fval(r->terrain, LAND_REGION) && !fval(terrain, LAND_REGION))) { + terraform_region(r, terrain); + } tp = &t->nexthash; } } @@ -873,9 +881,9 @@ static void select_regions(state * st, int selectmode) } static void loaddata(state *st) { - char datafile[MAX_PATH]; + char datafile[PATH_MAX]; - askstring(st->wnd_status->handle, "save as:", datafile, sizeof(datafile)); + askstring(st->wnd_status->handle, "load from:", datafile, sizeof(datafile)); if (strlen(datafile) > 0) { readgame(datafile); st->modified = 0; @@ -883,7 +891,7 @@ static void loaddata(state *st) { } static void savedata(state *st) { - char datafile[MAX_PATH]; + char datafile[PATH_MAX]; askstring(st->wnd_status->handle, "save as:", datafile, sizeof(datafile)); if (strlen(datafile) > 0) { @@ -1230,7 +1238,7 @@ static void handlekey(state * st, int c) else if (findmode == 'F') { faction *f = select_faction(st); if (f != NULL) { - strlcpy(locate, itoa36(f->no), sizeof(locate)); + itoab_r(f->no, 36, locate, sizeof(locate)); findmode = 'f'; } else { @@ -1256,7 +1264,7 @@ static void handlekey(state * st, int c) region *first = (mr && mr->r && mr->r->next) ? mr->r->next : regions; if (findmode == 'f') { - slprintf(sbuffer, sizeof(sbuffer), "find-faction: %s", locate); + snprintf(sbuffer, sizeof(sbuffer), "find-faction: %s", locate); statusline(st->wnd_status->handle, sbuffer); f = findfaction(atoi36(locate)); if (f == NULL) { @@ -1385,7 +1393,7 @@ void run_mapper(void) char sbuffer[512]; if (!new_players) { - join_path(basepath(), "newfactions", sbuffer, sizeof(sbuffer)); + path_join(basepath(), "newfactions", sbuffer, sizeof(sbuffer)); new_players = read_newfactions(sbuffer); } diff --git a/src/gmtool.h b/src/gmtool.h index 04f062f4b..5a2449c9a 100644 --- a/src/gmtool.h +++ b/src/gmtool.h @@ -11,6 +11,9 @@ #ifndef H_GMTOOL #define H_GMTOOL +#include +#include + #ifdef __cplusplus extern "C" { #endif diff --git a/src/guard.test.c b/src/guard.test.c index 8302bcc9a..6264aad21 100644 --- a/src/guard.test.c +++ b/src/guard.test.c @@ -23,16 +23,16 @@ static void test_is_guarded(CuTest *tc) { region *r; race *rc; - test_cleanup(); + test_setup(); rc = rc_get_or_create("dragon"); rc->flags |= RCF_UNARMEDGUARD; - r = test_create_region(0, 0, 0); - u1 = test_create_unit(test_create_faction(0), r); + r = test_create_region(0, 0, NULL); + u1 = test_create_unit(test_create_faction(NULL), r); u2 = test_create_unit(test_create_faction(rc), r); CuAssertPtrEquals(tc, 0, is_guarded(r, u1)); setguard(u2, true); CuAssertPtrEquals(tc, u2, is_guarded(r, u1)); - test_cleanup(); + test_teardown(); } static void test_guard_unskilled(CuTest * tc) @@ -44,15 +44,20 @@ static void test_guard_unskilled(CuTest * tc) test_setup(); itype = it_get_or_create(rt_get_or_create("sword")); - new_weapontype(itype, 0, frac_zero, NULL, 0, 0, 0, SK_MELEE, 2); - r = test_create_region(0, 0, 0); - u = test_create_unit(test_create_faction(0), r); - ug = test_create_unit(test_create_faction(0), r); + new_weapontype(itype, 0, frac_zero, NULL, 0, 0, 0, SK_MELEE); + r = test_create_region(0, 0, NULL); + u = test_create_unit(test_create_faction(NULL), r); + ug = test_create_unit(test_create_faction(NULL), r); i_change(&ug->items, itype, 1); + + setguard(ug, true); + CuAssertPtrEquals(tc, NULL, is_guarded(r, u)); + set_level(ug, SK_MELEE, 1); setguard(ug, true); - CuAssertPtrEquals(tc, 0, is_guarded(r, u)); - test_cleanup(); + CuAssertPtrEquals(tc, ug, is_guarded(r, u)); + + test_teardown(); } static void test_guard_armed(CuTest * tc) @@ -63,15 +68,15 @@ static void test_guard_armed(CuTest * tc) test_setup(); itype = it_get_or_create(rt_get_or_create("sword")); - new_weapontype(itype, 0, frac_zero, NULL, 0, 0, 0, SK_MELEE, 2); - r = test_create_region(0, 0, 0); - u = test_create_unit(test_create_faction(0), r); - ug = test_create_unit(test_create_faction(0), r); + new_weapontype(itype, 0, frac_zero, NULL, 0, 0, 0, SK_MELEE); + r = test_create_region(0, 0, NULL); + u = test_create_unit(test_create_faction(NULL), r); + ug = test_create_unit(test_create_faction(NULL), r); i_change(&ug->items, itype, 1); set_level(ug, SK_MELEE, 2); setguard(ug, true); CuAssertPtrEquals(tc, ug, is_guarded(r, u)); - test_cleanup(); + test_teardown(); } static void test_is_guard(CuTest * tc) @@ -82,21 +87,17 @@ static void test_is_guard(CuTest * tc) test_setup(); itype = it_get_or_create(rt_get_or_create("sword")); - new_weapontype(itype, 0, frac_zero, NULL, 0, 0, 0, SK_MELEE, 2); - r = test_create_region(0, 0, 0); - ug = test_create_unit(test_create_faction(0), r); + new_weapontype(itype, 0, frac_zero, NULL, 0, 0, 0, SK_MELEE); + r = test_create_region(0, 0, NULL); + ug = test_create_unit(test_create_faction(NULL), r); i_change(&ug->items, itype, 1); - set_level(ug, SK_MELEE, 2); setguard(ug, true); - CuAssertIntEquals(tc, 1, armedmen(ug, false)); - CuAssertTrue(tc, is_guard(ug)); - set_level(ug, SK_MELEE, 1); CuAssertIntEquals(tc, 0, armedmen(ug, false)); CuAssertTrue(tc, !is_guard(ug)); - set_level(ug, SK_MELEE, 2); + set_level(ug, SK_MELEE, 1); CuAssertIntEquals(tc, 1, armedmen(ug, false)); CuAssertTrue(tc, is_guard(ug)); - test_cleanup(); + test_teardown(); } static void test_guard_unarmed(CuTest * tc) @@ -108,12 +109,12 @@ static void test_guard_unarmed(CuTest * tc) test_setup(); rc = test_create_race("mountainguard"); rc->flags |= RCF_UNARMEDGUARD; - r = test_create_region(0, 0, 0); - u = test_create_unit(test_create_faction(0), r); + r = test_create_region(0, 0, NULL); + u = test_create_unit(test_create_faction(NULL), r); ug = test_create_unit(test_create_faction(rc), r); setguard(ug, true); CuAssertPtrEquals(tc, ug, is_guarded(r, u)); - test_cleanup(); + test_teardown(); } static void test_guard_monsters(CuTest * tc) @@ -122,12 +123,12 @@ static void test_guard_monsters(CuTest * tc) region *r; test_setup(); - r = test_create_region(0, 0, 0); - u = test_create_unit(test_create_faction(0), r); + r = test_create_region(0, 0, NULL); + u = test_create_unit(test_create_faction(NULL), r); ug = test_create_unit(get_monsters(), r); setguard(ug, true); CuAssertPtrEquals(tc, ug, is_guarded(r, u)); - test_cleanup(); + test_teardown(); } static void test_update_guard(CuTest * tc) @@ -142,11 +143,11 @@ static void test_update_guard(CuTest * tc) t_ocean = test_create_terrain("ocean", SEA_REGION); t_plain = test_create_terrain("packice", ARCTIC_REGION); itype = it_get_or_create(rt_get_or_create("sword")); - new_weapontype(itype, 0, frac_zero, NULL, 0, 0, 0, SK_MELEE, 2); + new_weapontype(itype, 0, frac_zero, NULL, 0, 0, 0, SK_MELEE); r = test_create_region(0, 0, t_plain); - ug = test_create_unit(test_create_faction(0), r); + ug = test_create_unit(test_create_faction(NULL), r); i_change(&ug->items, itype, 1); - set_level(ug, SK_MELEE, 2); + set_level(ug, SK_MELEE, 1); setguard(ug, true); CuAssertIntEquals(tc, 1, armedmen(ug, false)); CuAssertTrue(tc, is_guard(ug)); @@ -155,7 +156,7 @@ static void test_update_guard(CuTest * tc) update_guards(); CuAssertTrue(tc, ! is_guard(ug)); - test_cleanup(); + test_teardown(); } static void test_guard_on(CuTest * tc) @@ -169,11 +170,11 @@ static void test_guard_on(CuTest * tc) t_ocean = test_create_terrain("ocean", SEA_REGION); t_plain = test_create_terrain("plain", LAND_REGION); itype = it_get_or_create(rt_get_or_create("sword")); - new_weapontype(itype, 0, frac_zero, NULL, 0, 0, 0, SK_MELEE, 2); + new_weapontype(itype, 0, frac_zero, NULL, 0, 0, 0, SK_MELEE); r = test_create_region(0, 0, t_plain); - ug = test_create_unit(test_create_faction(0), r); + ug = test_create_unit(test_create_faction(NULL), r); i_change(&ug->items, itype, 1); - set_level(ug, SK_MELEE, 2); + set_level(ug, SK_MELEE, 1); ug->thisorder = create_order(K_GUARD, ug->faction->locale, NULL); setguard(ug, false); @@ -228,7 +229,7 @@ static void test_guard_on(CuTest * tc) config_set("NewbieImmunity", NULL); test_clear_messages(ug->faction); - test_cleanup(); + test_teardown(); } CuSuite *get_guard_suite(void) diff --git a/src/helpers.c b/src/helpers.c index 5f73ac542..b5c4c05ba 100644 --- a/src/helpers.c +++ b/src/helpers.c @@ -10,18 +10,21 @@ This program may not be used, modified or distributed without prior permission by the authors of Eressea. */ +#ifdef _MSC_VER #include +#endif + #include "helpers.h" #include "vortex.h" #include "alchemy.h" #include #include -#include #include #include #include #include +#include #include #include @@ -52,66 +55,65 @@ lua_giveitem(unit * s, unit * d, const item_type * itype, int n, struct order *o { lua_State *L = (lua_State *)global.vm_state; char fname[64]; - int result = -1; + int result = -1, len; const char *iname = itype->rtype->_name; + UNUSED_ARG(ord); assert(s != NULL); - strlcpy(fname, iname, sizeof(fname)); - strlcat(fname, "_give", sizeof(fname)); - - lua_getglobal(L, fname); - if (lua_isfunction(L, -1)) { - tolua_pushusertype(L, s, TOLUA_CAST "unit"); - tolua_pushusertype(L, d, TOLUA_CAST "unit"); - tolua_pushstring(L, iname); - lua_pushinteger(L, n); - - if (lua_pcall(L, 4, 1, 0) != 0) { - const char *error = lua_tostring(L, -1); - log_error("unit %s calling '%s': %s.\n", unitname(s), fname, error); - lua_pop(L, 1); + len = snprintf(fname, sizeof(fname), "%s_give", iname); + if (len > 0 && (size_t)len < sizeof(fname)) { + lua_getglobal(L, fname); + if (lua_isfunction(L, -1)) { + tolua_pushusertype(L, s, TOLUA_CAST "unit"); + tolua_pushusertype(L, d, TOLUA_CAST "unit"); + tolua_pushstring(L, iname); + lua_pushinteger(L, n); + + if (lua_pcall(L, 4, 1, 0) != 0) { + const char *error = lua_tostring(L, -1); + log_error("unit %s calling '%s': %s.\n", unitname(s), fname, error); + lua_pop(L, 1); + } + else { + result = (int)lua_tonumber(L, -1); + lua_pop(L, 1); + } } else { - result = (int)lua_tonumber(L, -1); + log_error("unit %s trying to call '%s' : not a function.\n", unitname(s), fname); lua_pop(L, 1); } } - else { - log_error("unit %s trying to call '%s' : not a function.\n", unitname(s), fname); - lua_pop(L, 1); - } - return result; } static int limit_resource_lua(const region * r, const resource_type * rtype) { char fname[64]; - int result = -1; + int result = -1, len; lua_State *L = (lua_State *)global.vm_state; - strlcpy(fname, rtype->_name, sizeof(fname)); - strlcat(fname, "_limit", sizeof(fname)); + len = snprintf(fname, sizeof(fname), "%s_limit", rtype->_name); + if (len > 0 && (size_t)len < sizeof(fname)) { + lua_getglobal(L, fname); + if (lua_isfunction(L, -1)) { + tolua_pushusertype(L, (void *)r, TOLUA_CAST "region"); - lua_getglobal(L, fname); - if (lua_isfunction(L, -1)) { - tolua_pushusertype(L, (void *)r, TOLUA_CAST "region"); - - if (lua_pcall(L, 1, 1, 0) != 0) { - const char *error = lua_tostring(L, -1); - log_error("limit(%s) calling '%s': %s.\n", regionname(r, NULL), fname, error); - lua_pop(L, 1); + if (lua_pcall(L, 1, 1, 0) != 0) { + const char *error = lua_tostring(L, -1); + log_error("limit(%s) calling '%s': %s.\n", regionname(r, NULL), fname, error); + lua_pop(L, 1); + } + else { + result = (int)lua_tonumber(L, -1); + lua_pop(L, 1); + } } else { - result = (int)lua_tonumber(L, -1); + log_error("limit(%s) calling '%s': not a function.\n", regionname(r, NULL), fname); lua_pop(L, 1); } } - else { - log_error("limit(%s) calling '%s': not a function.\n", regionname(r, NULL), fname); - lua_pop(L, 1); - } - return result; } @@ -120,25 +122,26 @@ produce_resource_lua(region * r, const resource_type * rtype, int norders) { lua_State *L = (lua_State *)global.vm_state; char fname[64]; - - strlcpy(fname, rtype->_name, sizeof(fname)); - strlcat(fname, "_produce", sizeof(fname)); - - lua_getglobal(L, fname); - if (lua_isfunction(L, -1)) { - tolua_pushusertype(L, (void *)r, TOLUA_CAST "region"); - lua_pushinteger(L, norders); - - if (lua_pcall(L, 2, 0, 0) != 0) { - const char *error = lua_tostring(L, -1); - log_error("produce(%s) calling '%s': %s.\n", regionname(r, NULL), fname, error); + int len; + + len = snprintf(fname, sizeof(fname), "%s_produce", rtype->_name); + if (len > 0 && (size_t)len < sizeof(fname)) { + lua_getglobal(L, fname); + if (lua_isfunction(L, -1)) { + tolua_pushusertype(L, (void *)r, TOLUA_CAST "region"); + lua_pushinteger(L, norders); + + if (lua_pcall(L, 2, 0, 0) != 0) { + const char *error = lua_tostring(L, -1); + log_error("produce(%s) calling '%s': %s.\n", regionname(r, NULL), fname, error); + lua_pop(L, 1); + } + } + else { + log_error("produce(%s) calling '%s': not a function.\n", regionname(r, NULL), fname); lua_pop(L, 1); } } - else { - log_error("produce(%s) calling '%s': not a function.\n", regionname(r, NULL), fname); - lua_pop(L, 1); - } } static void push_param(lua_State * L, char c, spllprm * param) @@ -216,32 +219,31 @@ static int lua_changeresource(unit * u, const struct resource_type *rtype, int delta) { lua_State *L = (lua_State *)global.vm_state; - int result = -1; + int len, result = -1; char fname[64]; - strlcpy(fname, rtype->_name, sizeof(fname)); - strlcat(fname, "_changeresource", sizeof(fname)); - - lua_getglobal(L, fname); - if (lua_isfunction(L, -1)) { - tolua_pushusertype(L, u, TOLUA_CAST "unit"); - lua_pushinteger(L, delta); - - if (lua_pcall(L, 2, 1, 0) != 0) { - const char *error = lua_tostring(L, -1); - log_error("change(%s) calling '%s': %s.\n", unitname(u), fname, error); - lua_pop(L, 1); + len = snprintf(fname, sizeof(fname), "%s_changeresource", rtype->_name); + if (len > 0 && (size_t)len < sizeof(fname)) { + lua_getglobal(L, fname); + if (lua_isfunction(L, -1)) { + tolua_pushusertype(L, u, TOLUA_CAST "unit"); + lua_pushinteger(L, delta); + + if (lua_pcall(L, 2, 1, 0) != 0) { + const char *error = lua_tostring(L, -1); + log_error("change(%s) calling '%s': %s.\n", unitname(u), fname, error); + lua_pop(L, 1); + } + else { + result = (int)lua_tonumber(L, -1); + lua_pop(L, 1); + } } else { - result = (int)lua_tonumber(L, -1); + log_error("change(%s) calling '%s': not a function.\n", unitname(u), fname); lua_pop(L, 1); } } - else { - log_error("change(%s) calling '%s': not a function.\n", unitname(u), fname); - lua_pop(L, 1); - } - return result; } @@ -250,13 +252,12 @@ static int use_item_lua(unit *u, const item_type *itype, int amount, struct order *ord) { lua_State *L = (lua_State *)global.vm_state; - int result = 0; + int len, result = 0; char fname[64]; int (*callout)(unit *, const item_type *, int, struct order *); - strlcpy(fname, "use_", sizeof(fname)); - strlcat(fname, itype->rtype->_name, sizeof(fname)); - + len = snprintf(fname, sizeof(fname), "use_%s", itype->rtype->_name); + if (len > 0 && (size_t)len < sizeof(fname)) { callout = (int(*)(unit *, const item_type *, int, struct order *))get_function(fname); if (callout) { return callout(u, itype, amount, ord); @@ -280,13 +281,13 @@ use_item_lua(unit *u, const item_type *itype, int amount, struct order *ord) return result; } lua_pop(L, 1); - if (itype->rtype->ptype) { + if (itype->flags & ITF_POTION) { return use_potion(u, itype, amount, ord); } else { log_error("no such callout: %s", fname); } log_error("use(%s) calling '%s': not a function.\n", unitname(u), fname); - + } return result; } @@ -304,11 +305,27 @@ struct trigger_type tt_caldera = { caldera_read }; + +static int building_action_read(struct attrib *a, void *owner, gamedata *data) +{ + struct storage *store = data->store; + + UNUSED_ARG(owner); + UNUSED_ARG(a); + + if (data->version < ATTRIBOWNER_VERSION) { + READ_INT(data->store, NULL); + } + READ_TOK(store, NULL, 0); + READ_TOK(store, NULL, 0); + return AT_READ_DEPR; +} + void register_tolua_helpers(void) { tt_register(&tt_caldera); at_register(&at_direction); - at_register(&at_building_action); + at_deprecate("lcbuilding", building_action_read); callbacks.cast_spell = lua_callspell; callbacks.use_item = use_item_lua; diff --git a/src/items.c b/src/items.c index 8a6328d91..ba9f35388 100644 --- a/src/items.c +++ b/src/items.c @@ -1,30 +1,31 @@ +#ifdef _MSC_VER #include +#endif #include "items.h" #include "alchemy.h" +#include "skill.h" +#include "keyword.h" +#include "direction.h" #include "study.h" #include "economy.h" -#include "move.h" #include "magic.h" -#include - #include #include #include #include -#include #include #include #include #include -#include #include #include #include #include #include +#include #include /* triggers includes */ @@ -33,12 +34,13 @@ #include #include -#include +#include #include #include #include #include +#include #include /* BEGIN studypotion */ @@ -47,7 +49,7 @@ static int use_studypotion(struct unit *u, const struct item_type *itype, int amount, struct order *ord) { - if (u->thisorder && init_order(u->thisorder) == K_STUDY) { + if (u->thisorder && init_order(u->thisorder, u->faction->locale) == K_STUDY) { char token[128]; skill_t sk = NOSKILL; skill *sv = 0; @@ -266,7 +268,7 @@ static int use_foolpotion(unit *u, const item_type *itype, int amount, ADDMSG(&u->faction->msgs, msg_message("givedumb", "unit recipient amount", u, target, amount)); - change_effect(target, itype->rtype->ptype, amount); + change_effect(target, itype, amount); use_pooled(u, itype->rtype, GET_DEFAULT, amount); return 0; } @@ -276,7 +278,7 @@ use_bloodpotion(struct unit *u, const struct item_type *itype, int amount, struct order *ord) { if (u->number == 0 || u_race(u) == get_race(RC_DAEMON)) { - change_effect(u, itype->rtype->ptype, 100 * amount); + change_effect(u, itype, 100 * amount); } else { const race *irace = u_irace(u); @@ -300,7 +302,7 @@ struct order *ord) } use_pooled(u, itype->rtype, GET_SLACK | GET_RESERVE | GET_POOLED_SLACK, amount); - usetpotionuse(u, itype->rtype->ptype); + usetpotionuse(u, itype); ADDMSG(&u->faction->msgs, msg_message("usepotion", "unit potion", u, itype->rtype)); @@ -311,7 +313,7 @@ static int heal(unit * user, int effect) { int req = unit_max_hp(user) * user->number - user->hp; if (req > 0) { - req = MIN(req, effect); + if (req > effect) req = effect; effect -= req; user->hp += req; } @@ -333,7 +335,7 @@ struct order *ord) } use_pooled(user, itype->rtype, GET_SLACK | GET_RESERVE | GET_POOLED_SLACK, amount); - usetpotionuse(user, itype->rtype->ptype); + usetpotionuse(user, itype); ADDMSG(&user->faction->msgs, msg_message("usepotion", "unit potion", user, itype->rtype)); @@ -372,21 +374,18 @@ static int use_mistletoe(struct unit *user, const struct item_type *itype, int amount, struct order *ord) { - int mtoes = - get_pooled(user, itype->rtype, GET_SLACK | GET_RESERVE | GET_POOLED_SLACK, - user->number); - - if (user->number > mtoes) { - ADDMSG(&user->faction->msgs, msg_message("use_singleperson", - "unit item region command", user, itype->rtype, user->region, ord)); - return -1; + int mtoes = get_pooled(user, itype->rtype, + GET_SLACK | GET_RESERVE | GET_POOLED_SLACK, amount); + if (mtoes < amount) { + amount = mtoes; + } + if (amount > 0) { + use_pooled(user, itype->rtype, + GET_SLACK | GET_RESERVE | GET_POOLED_SLACK, amount); + change_effect(user, itype, amount); + ADDMSG(&user->faction->msgs, + msg_message("use_item", "unit amount item", user, amount, itype->rtype)); } - use_pooled(user, itype->rtype, GET_SLACK | GET_RESERVE | GET_POOLED_SLACK, - user->number); - a_add(&user->attribs, make_fleechance((float)1.0)); - ADDMSG(&user->faction->msgs, - msg_message("use_item", "unit item", user, itype->rtype)); - return 0; } @@ -403,7 +402,7 @@ static int use_warmthpotion(unit *u, const item_type *itype, } use_pooled(u, itype->rtype, GET_SLACK | GET_RESERVE | GET_POOLED_SLACK, amount); - usetpotionuse(u, itype->rtype->ptype); + usetpotionuse(u, itype); ADDMSG(&u->faction->msgs, msg_message("usepotion", "unit potion", u, itype->rtype)); diff --git a/src/items/speedsail.c b/src/items/speedsail.c index cb40e9a8c..b224d6d6d 100644 --- a/src/items/speedsail.c +++ b/src/items/speedsail.c @@ -33,6 +33,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* util includes */ #include #include +#include /* libc includes */ #include diff --git a/src/items/weapons.c b/src/items/weapons.c index acb47f0e0..53721bca6 100644 --- a/src/items/weapons.c +++ b/src/items/weapons.c @@ -76,7 +76,7 @@ int *casualties) killed += terminate(dt, *at, AT_SPELL, damage, 1); } } while (force && killed < enemies); - if (casualties) + if (killed > 0 && casualties) *casualties = killed; return true; } diff --git a/src/items/xerewards.c b/src/items/xerewards.c index e9a11d00d..71746bbf3 100644 --- a/src/items/xerewards.c +++ b/src/items/xerewards.c @@ -65,17 +65,18 @@ struct order *ord) int use_manacrystal(struct unit *u, const struct item_type *itype, int amount, -struct order *ord) + struct order *ord) { - int i, sp = 0; + int i, sp = 0, msp; if (!is_mage(u)) { cmistake(u, u->thisorder, 295, MSG_EVENT); return -1; } + msp = max_spellpoints(u->region, u) / 2; for (i = 0; i != amount; ++i) { - sp += MAX(25, max_spellpoints(u->region, u) / 2); + sp += MAX(25, msp); change_spellpoints(u, sp); } diff --git a/src/items/xerewards.test.c b/src/items/xerewards.test.c index 5739141c0..c0d20079e 100644 --- a/src/items/xerewards.test.c +++ b/src/items/xerewards.test.c @@ -2,19 +2,42 @@ #include "xerewards.h" #include "study.h" +#include "magic.h" -#include +#include #include #include #include +#include #include #include static void test_manacrystal(CuTest *tc) { - test_cleanup(); - test_create_world(); - test_cleanup(); + struct item_type *itype; + unit *u; + + test_setup(); + test_inject_messagetypes(); + + u = test_create_unit(test_create_faction(NULL), test_create_plain(0, 0)); + itype = test_create_itemtype("manacrystal"); + change_resource(u, itype->rtype, 1); + CuAssertIntEquals(tc, -1, use_manacrystal(u, itype, 1, NULL)); + CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "error295")); + test_clear_messages(u->faction); + create_mage(u, M_GRAY); + set_level(u, SK_MAGIC, 5); + CuAssertIntEquals(tc, 0, get_spellpoints(u)); + CuAssertIntEquals(tc, 1, use_manacrystal(u, itype, 1, NULL)); + CuAssertIntEquals(tc, 25, get_spellpoints(u)); + CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "manacrystal_use")); + test_clear_messages(u->faction); + set_level(u, SK_MAGIC, 8); + CuAssertIntEquals(tc, 1, use_manacrystal(u, itype, 1, NULL)); + CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "manacrystal_use")); + CuAssertIntEquals(tc, 25 + 33, get_spellpoints(u)); + test_teardown(); } static void test_skillpotion(CuTest *tc) { @@ -25,9 +48,9 @@ static void test_skillpotion(CuTest *tc) { int initialWeeks_Stamina = 0; int initialWeeks_Magic = 0; - test_cleanup(); - test_create_world(); - u = test_create_unit(test_create_faction(NULL), findregion(0, 0)); + test_setup(); + test_inject_messagetypes(); + u = test_create_unit(test_create_faction(NULL), test_create_plain(0, 0)); itype = test_create_itemtype("skillpotion"); change_resource(u, itype->rtype, 2); @@ -57,7 +80,7 @@ static void test_skillpotion(CuTest *tc) { pSkill = unit_skill(u, SK_MAGIC); CuAssertIntEquals(tc, initialWeeks_Magic - 3, pSkill->weeks); - test_cleanup(); + test_teardown(); } CuSuite *get_xerewards_suite(void) diff --git a/src/json.c b/src/json.c index e6eacced9..127d74f70 100644 --- a/src/json.c +++ b/src/json.c @@ -102,7 +102,7 @@ int json_export(stream * out, int flags) { cJSON *data; cJSON_AddItemToObject(json, itoa36(f->no), data = cJSON_CreateObject()); cJSON_AddStringToObject(data, "name", f->name); - cJSON_AddStringToObject(data, "email", f->email); + cJSON_AddStringToObject(data, "email", faction_getemail(f)); cJSON_AddNumberToObject(data, "score", (double)f->score); } } diff --git a/src/json.test.c b/src/json.test.c index 57cb6e136..48a5e4be6 100644 --- a/src/json.test.c +++ b/src/json.test.c @@ -1,19 +1,22 @@ #include -#include -#include -#include + +#include "json.h" +#include "tests.h" #include #include -#include "json.h" -#include "tests.h" +#include +#include #include +#include + #include #include #include + static char *strip(char *str) { char *s = str, *b = str, *e = str; /* b is where text begins, e where it ends, s where we insert it. */ @@ -37,6 +40,7 @@ static void test_export_no_regions(CuTest * tc) { int err; size_t len; + test_setup(); mstream_init(&out); err = json_export(&out, EXPORT_REGIONS); CuAssertIntEquals(tc, 0, err); @@ -45,7 +49,7 @@ static void test_export_no_regions(CuTest * tc) { buf[len] = '\0'; CuAssertStrEquals(tc, "{}", strip(buf)); mstream_done(&out); - test_cleanup(); + test_teardown(); } static cJSON *export_a_region(CuTest * tc, const struct terrain_type *terrain, region **_r) { @@ -90,24 +94,26 @@ static void test_export_land_region(CuTest * tc) { region *r; struct terrain_type *terrain; cJSON *json, *attr; - test_cleanup(); + + test_setup(); terrain = test_create_terrain("plain", LAND_REGION); json = export_a_region(tc, terrain, &r); CuAssertPtrNotNull(tc, attr = cJSON_GetObjectItem(json, "name")); CuAssertStrEquals(tc, r->land->name, attr->valuestring); cJSON_Delete(json); - test_cleanup(); + test_teardown(); } static void test_export_ocean_region(CuTest * tc) { struct terrain_type *terrain; cJSON *json; - test_cleanup(); + + test_setup(); terrain = test_create_terrain("ocean", SEA_REGION); json = export_a_region(tc, terrain, 0); CuAssertPtrEquals(tc, 0, cJSON_GetObjectItem(json, "name")); cJSON_Delete(json); - test_cleanup(); + test_teardown(); } static void test_export_no_factions(CuTest * tc) { @@ -116,6 +122,7 @@ static void test_export_no_factions(CuTest * tc) { int err; size_t len; + test_setup(); mstream_init(&out); err = json_export(&out, EXPORT_FACTIONS); CuAssertIntEquals(tc, 0, err); @@ -124,7 +131,7 @@ static void test_export_no_factions(CuTest * tc) { buf[len] = 0; CuAssertStrEquals(tc, "{}", strip(buf)); mstream_done(&out); - test_cleanup(); + test_teardown(); } CuSuite *get_json_suite(void) { diff --git a/src/kernel/jsonconf.c b/src/jsonconf.c similarity index 97% rename from src/kernel/jsonconf.c rename to src/jsonconf.c index 609e73aac..3c5411b9d 100644 --- a/src/kernel/jsonconf.c +++ b/src/jsonconf.c @@ -15,38 +15,38 @@ without prior permission by the authors of Eressea. #include "jsonconf.h" /* kernel includes */ -#include "building.h" -#include "direction.h" -#include "keyword.h" -#include "equipment.h" -#include "item.h" -#include "messages.h" -#include "race.h" -#include "region.h" -#include "resources.h" -#include "ship.h" -#include "terrain.h" -#include "skill.h" -#include "spell.h" -#include "spellbook.h" -#include "calendar.h" - -/* game modules */ -#include "prefix.h" -#include "move.h" -#include "calendar.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* util includes */ #include -#include #include #include #include #include #include #include +#include +#include #include +/* game modules */ +#include "calendar.h" +#include "direction.h" +#include "keyword.h" +#include "move.h" +#include "prefix.h" +#include "skill.h" + /* external libraries */ #include @@ -228,7 +228,7 @@ static void json_terrain_production(cJSON *json, terrain_production *prod) { if (dst) { free(*dst); assert(child->type == cJSON_String); - *dst = strdup(child->valuestring); + *dst = str_strdup(child->valuestring); } } } @@ -452,7 +452,7 @@ static void json_race(cJSON *json, race *rc) { switch (child->type) { case cJSON_String: if (strcmp(child->string, "damage") == 0) { - rc->def_damage = strdup(child->valuestring); + rc->def_damage = str_strdup(child->valuestring); } break; case cJSON_Number: @@ -592,7 +592,7 @@ static void json_spells(cJSON *json) { continue; } else if (strcmp(item->string, "syntax") == 0) { - sp->syntax = strdup(item->valuestring); + sp->syntax = str_strdup(item->valuestring); } } } @@ -703,7 +703,7 @@ static void json_calendar(cJSON *json) { weeknames = malloc(sizeof(char *) * weeks_per_month); for (i = 0, entry = child->child; entry; entry = entry->next, ++i) { if (entry->type == cJSON_String) { - weeknames[i] = strdup(entry->valuestring); + weeknames[i] = str_strdup(entry->valuestring); } else { log_error("calendar.weeks[%d] is not a string: %d", i, json->type); @@ -896,8 +896,8 @@ static void json_include(cJSON *json) { for (child = json->child; child; child = child->next) { FILE *F; if (json_relpath) { - char name[MAX_PATH]; - join_path(json_relpath, child->valuestring, name, sizeof(name)); + char name[PATH_MAX]; + path_join(json_relpath, child->valuestring, name, sizeof(name)); F = fopen(name, "r"); } else { diff --git a/src/kernel/jsonconf.h b/src/jsonconf.h similarity index 100% rename from src/kernel/jsonconf.h rename to src/jsonconf.h diff --git a/src/kernel/jsonconf.test.c b/src/jsonconf.test.c similarity index 96% rename from src/kernel/jsonconf.test.c rename to src/jsonconf.test.c index cb79cafc4..29c68e600 100644 --- a/src/kernel/jsonconf.test.c +++ b/src/jsonconf.test.c @@ -1,24 +1,28 @@ +#ifdef _MSC_VER #include -#include "types.h" +#endif + +#include "kernel/types.h" + #include "jsonconf.h" -#include "config.h" -#include "building.h" +#include "kernel/config.h" +#include "kernel/building.h" +#include "kernel/item.h" +#include "kernel/race.h" +#include "kernel/ship.h" +#include "kernel/spell.h" +#include "kernel/order.h" +#include "kernel/terrain.h" + +#include "util/language.h" + +#include "calendar.h" #include "direction.h" -#include "item.h" #include "keyword.h" -#include "race.h" -#include "ship.h" -#include "spell.h" -#include "order.h" -#include "terrain.h" - #include "move.h" -#include "calendar.h" #include "prefix.h" -#include "util/language.h" - #include #include #include @@ -51,6 +55,7 @@ static void check_flag(CuTest *tc, const char *name, int flag) { } static void test_flags(CuTest *tc) { + test_setup(); check_flag(tc, "npc", RCF_NPC); check_flag(tc, "scarepeasants", RCF_SCAREPEASANTS); check_flag(tc, "nosteal", RCF_NOSTEAL); @@ -61,7 +66,7 @@ static void test_flags(CuTest *tc) { check_ec_flag(tc, "getitem", ECF_GETITEM); check_ec_flag(tc, "giveperson", ECF_GIVEPERSON); check_ec_flag(tc, "giveunit", ECF_GIVEUNIT); - test_cleanup(); + test_teardown(); } static void test_settings(CuTest * tc) @@ -88,7 +93,7 @@ static void test_settings(CuTest * tc) CuAssertIntEquals(tc, 14, config_get_int("integer", 0)); CuAssertDblEquals(tc, 1.5f, config_get_flt("float", 0), 0.01); cJSON_Delete(json); - test_cleanup(); + test_teardown(); } static void test_prefixes(CuTest * tc) @@ -107,7 +112,7 @@ static void test_prefixes(CuTest * tc) CuAssertStrEquals(tc, "dark", race_prefixes[2]); CuAssertPtrEquals(tc, 0, race_prefixes[3]); cJSON_Delete(json); - test_cleanup(); + test_teardown(); } static void test_disable(CuTest * tc) @@ -133,7 +138,7 @@ static void test_disable(CuTest * tc) CuAssertTrue(tc, keyword_disabled(K_BESIEGE)); CuAssertIntEquals(tc, 0, config_get_int("module.enabled", 1)); cJSON_Delete(json); - test_cleanup(); + test_teardown(); } static void test_calendar(CuTest * tc) @@ -158,7 +163,7 @@ static void test_calendar(CuTest * tc) CuAssertIntEquals(tc, 1, month_season[0]); CuAssertIntEquals(tc, 2, month_season[1]); cJSON_Delete(json); - test_cleanup(); + test_teardown(); } static void test_races(CuTest * tc) @@ -205,7 +210,7 @@ static void test_races(CuTest * tc) CuAssertIntEquals(tc, 5, rc->hitpoints); CuAssertIntEquals(tc, 6, rc->armor); cJSON_Delete(json); - test_cleanup(); + test_teardown(); } static void test_findrace(CuTest *tc) { @@ -225,7 +230,7 @@ static void test_findrace(CuTest *tc) { CuAssertPtrNotNull(tc, rc); CuAssertStrEquals(tc, "dwarf", rc->_name); cJSON_Delete(json); - test_cleanup(); + test_teardown(); } static void test_items(CuTest * tc) @@ -259,7 +264,7 @@ static void test_items(CuTest * tc) CuAssertPtrNotNull(tc, rt_find("axe")); CuAssertPtrNotNull(tc, (void *)get_resourcetype(R_HORSE)); cJSON_Delete(json); - test_cleanup(); + test_teardown(); } static void test_ships(CuTest * tc) @@ -299,7 +304,7 @@ static void test_ships(CuTest * tc) CuAssertPtrEquals(tc, 0, (void *)st->coasts[1]); cJSON_Delete(json); - test_cleanup(); + test_teardown(); } static void test_castles(CuTest *tc) { @@ -327,7 +332,7 @@ static void test_castles(CuTest *tc) { CuAssertIntEquals(tc, 6, bt->construction->improvement->maxsize); CuAssertPtrEquals(tc, 0, bt->construction->improvement->improvement); cJSON_Delete(json); - test_cleanup(); + test_teardown(); } static void test_spells(CuTest * tc) @@ -347,7 +352,7 @@ static void test_spells(CuTest * tc) CuAssertStrEquals(tc, "u+", sp->syntax); cJSON_Delete(json); - test_cleanup(); + test_teardown(); CuAssertPtrEquals(tc, 0, find_spell("fireball")); } @@ -413,7 +418,7 @@ static void test_buildings(CuTest * tc) CuAssertIntEquals(tc, 1, bt->construction->minskill); CuAssertPtrEquals(tc, 0, bt->construction->improvement); cJSON_Delete(json); - test_cleanup(); + test_teardown(); } static const char * building_defaults_data = "{\"buildings\": { " @@ -438,7 +443,7 @@ static void test_buildings_default(CuTest * tc) CuAssertPtrEquals(tc, (void *)bt, (void *)bt_find("house")); CuAssertIntEquals(tc, 0, memcmp(bt, &clone, sizeof(building_type))); cJSON_Delete(json); - test_cleanup(); + test_teardown(); } static const char * ship_defaults_data = "{\"ships\": { " @@ -463,7 +468,7 @@ static void test_ships_default(CuTest * tc) CuAssertPtrEquals(tc, (void *)st, (void *)st_find("hodor")); CuAssertIntEquals(tc, 0, memcmp(st, &clone, sizeof(ship_type))); cJSON_Delete(json); - test_cleanup(); + test_teardown(); } static void test_configs(CuTest * tc) @@ -485,7 +490,7 @@ static void test_configs(CuTest * tc) errno = 0; } cJSON_Delete(json); - test_cleanup(); + test_teardown(); } static void test_terrains(CuTest * tc) @@ -527,7 +532,7 @@ static void test_terrains(CuTest * tc) CuAssertPtrEquals(tc, 0, (void *)ter->production[2].type); cJSON_Delete(json); - test_cleanup(); + test_teardown(); } static void test_directions(CuTest * tc) @@ -549,7 +554,7 @@ static void test_directions(CuTest * tc) CuAssertIntEquals(tc, D_PAUSE, get_direction("pause", lang)); cJSON_Delete(json); - test_cleanup(); + test_teardown(); } static void test_skills(CuTest * tc) @@ -574,7 +579,7 @@ static void test_skills(CuTest * tc) CuAssertStrEquals(tc, "ARMBRUST", LOC(lang, "skill::crossbow")); cJSON_Delete(json); - test_cleanup(); + test_teardown(); } static void test_keywords(CuTest * tc) @@ -598,7 +603,7 @@ static void test_keywords(CuTest * tc) CuAssertStrEquals(tc, "NACH", LOC(lang, "keyword::move")); cJSON_Delete(json); - test_cleanup(); + test_teardown(); } static void test_strings(CuTest * tc) @@ -617,7 +622,7 @@ static void test_strings(CuTest * tc) CuAssertStrEquals(tc, "NACH", LOC(lang, "move")); CuAssertStrEquals(tc, "LERNEN", LOC(lang, "study")); cJSON_Delete(json); - test_cleanup(); + test_teardown(); } static void test_infinitive_from_config(CuTest *tc) { @@ -637,10 +642,10 @@ static void test_infinitive_from_config(CuTest *tc) { CuAssertIntEquals(tc, K_STUDY, get_keyword("LERNEN", lang)); ord = create_order(K_STUDY, lang, ""); - CuAssertStrEquals(tc, "LERNE", get_command(ord, buffer, sizeof(buffer))); + CuAssertStrEquals(tc, "LERNE", get_command(ord, lang, buffer, sizeof(buffer))); free_order(ord); cJSON_Delete(json); - test_cleanup(); + test_teardown(); } CuSuite *get_jsonconf_suite(void) diff --git a/src/kernel/CMakeLists.txt b/src/kernel/CMakeLists.txt index fe560af7a..cb8373fa2 100644 --- a/src/kernel/CMakeLists.txt +++ b/src/kernel/CMakeLists.txt @@ -11,12 +11,14 @@ command.test.c config.test.c # connection.test.c curse.test.c +database.test.c equipment.test.c faction.test.c group.test.c item.test.c messages.test.c order.test.c +orderdb.test.c # pathfinder.test.c plane.test.c pool.test.c @@ -25,16 +27,23 @@ region.test.c # resources.test.c save.test.c ship.test.c -# skills.test.c +skills.test.c spellbook.test.c spell.test.c # terrain.test.c unit.test.c -jsonconf.test.c -# xmlreader.test.c ) +SET(_DBFILES db/critbit.c) + +IF(SQLITE3_FOUND) +SET(_DBFILES db/sqlite.c) +ELSEIF(DB_FOUND) +SET(_DBFILES db/berkeley.c) +ENDIF(SQLITE3_FOUND) + SET(_FILES +${_DBFILES} alliance.c ally.c build.c @@ -44,12 +53,14 @@ command.c config.c connection.c curse.c +database.c equipment.c faction.c group.c item.c messages.c order.c +orderdb.c pathfinder.c plane.c pool.c @@ -64,8 +75,6 @@ spellbook.c spell.c terrain.c unit.c -xmlreader.c -jsonconf.c ) SET(VERSION_SRC ${PROJECT_NAME}/version.c PARENT_SCOPE) diff --git a/src/kernel/alliance.c b/src/kernel/alliance.c index 910670d10..1aa3edd95 100644 --- a/src/kernel/alliance.c +++ b/src/kernel/alliance.c @@ -28,10 +28,10 @@ without prior permission by the authors of Eressea. /* util includes */ #include #include -#include #include #include #include +#include #include #include @@ -40,6 +40,7 @@ without prior permission by the authors of Eressea. #include #include #include +#include alliance *alliances = NULL; @@ -83,13 +84,14 @@ alliance *new_alliance(int id, const char *name) { al = calloc(1, sizeof(alliance)); al->id = id; if (name) { - al->name = strdup(name); + al->name = str_strdup(name); } else { al->flags |= ALF_NON_ALLIED; } al->next = alliances; - return alliances = al; + alliances = al; + return al; } alliance *findalliance(int id) @@ -171,7 +173,7 @@ static void perform_kick(void) if (al && alliance_get_leader(al) == ta->u->faction) { faction *f; - init_order(ta->ord); + init_order_depr(ta->ord); skip_token(); f = getfaction(); if (f && f_get_alliance(f) == al) { @@ -192,7 +194,7 @@ static void perform_new(void) int id; faction *f = ta->u->faction; - init_order(ta->ord); + init_order_depr(ta->ord); skip_token(); id = getid(); @@ -227,7 +229,7 @@ static void perform_transfer(void) if (al && alliance_get_leader(al) == ta->u->faction) { faction *f; - init_order(ta->ord); + init_order_depr(ta->ord); skip_token(); f = getfaction(); if (f && f_get_alliance(f) == al) { @@ -264,7 +266,7 @@ static void perform_join(void) faction *fj = ta->u->faction; int aid; - init_order(ta->ord); + init_order_depr(ta->ord); skip_token(); aid = getid(); if (aid) { @@ -276,7 +278,7 @@ static void perform_join(void) faction *fi = ti->u->faction; if (fi && f_get_alliance(fi) == al) { int fid; - init_order(ti->ord); + init_order_depr(ti->ord); skip_token(); fid = getid(); if (fid == fj->no) { @@ -421,7 +423,7 @@ const char *alliancename(const alliance * al) char *ibuf = idbuf[(++nextbuf) % 8]; if (al && al->name) { - slprintf(ibuf, sizeof(name), "%s (%s)", al->name, itoa36(al->id)); + snprintf(ibuf, sizeof(idbuf[0]), "%s (%s)", al->name, itoa36(al->id)); } else { return NULL; @@ -429,51 +431,11 @@ const char *alliancename(const alliance * al) return ibuf; } -void alliancevictory(void) -{ - const struct building_type *btype = bt_find("stronghold"); - region *r = regions; - alliance *al = alliances; - if (btype == NULL) - return; - while (r != NULL) { - building *b = r->buildings; - while (b != NULL) { - if (b->type == btype) { - unit *u = building_owner(b); - if (u) { - fset(u->faction->alliance, FFL_MARK); - } - } - b = b->next; - } - r = r->next; - } - while (al != NULL) { - if (!fval(al, FFL_MARK)) { - faction **fp; - for (fp = &factions; *fp; ) { - faction *f = *fp; - if (f->alliance == al) { - ADDMSG(&f->msgs, msg_message("alliance::lost", "alliance", al)); - destroyfaction(fp); - } else { - fp = &f->next; - } - } - } - else { - freset(al, FFL_MARK); - } - al = al->next; - } -} - void alliance_setname(alliance * self, const char *name) { free(self->name); if (name) - self->name = strdup(name); + self->name = str_strdup(name); else self->name = NULL; } diff --git a/src/kernel/alliance.test.c b/src/kernel/alliance.test.c index 885bc8413..00fe1f4d9 100644 --- a/src/kernel/alliance.test.c +++ b/src/kernel/alliance.test.c @@ -42,7 +42,7 @@ static void test_alliance_make(CuTest *tc) { free_alliances(); CuAssertPtrEquals(tc, 0, findalliance(1)); CuAssertPtrEquals(tc, 0, alliances); - test_cleanup(); + test_teardown(); } static void test_alliance_join(CuTest *tc) { @@ -61,7 +61,7 @@ static void test_alliance_join(CuTest *tc) { setalliance(fix.f1, 0); CuAssertPtrEquals(tc, fix.f2, alliance_get_leader(al)); CuAssertTrue(tc, !is_allied(fix.f1, fix.f2)); - test_cleanup(); + test_teardown(); } static void test_alliance_dead_faction(CuTest *tc) { @@ -69,8 +69,8 @@ static void test_alliance_dead_faction(CuTest *tc) { alliance *al; test_setup(); - f = test_create_faction(0); - f2 = test_create_faction(0); + f = test_create_faction(NULL); + f2 = test_create_faction(NULL); al = makealliance(42, "Hodor"); setalliance(f, al); setalliance(f2, al); @@ -82,7 +82,7 @@ static void test_alliance_dead_faction(CuTest *tc) { CuAssertPtrEquals(tc, f2, alliance_get_leader(al)); CuAssertPtrEquals(tc, NULL, f->alliance); CuAssertTrue(tc, !f->_alive); - test_cleanup(); + test_teardown(); } static void test_alliance_cmd(CuTest *tc) { @@ -91,9 +91,9 @@ static void test_alliance_cmd(CuTest *tc) { struct alliance *al; test_setup(); - r = test_create_region(0, 0, 0); - u1 = test_create_unit(test_create_faction(0), r); - u2 = test_create_unit(test_create_faction(0), r); + r = test_create_region(0, 0, NULL); + u1 = test_create_unit(test_create_faction(NULL), r); + u2 = test_create_unit(test_create_faction(NULL), r); unit_addorder(u1, create_order(K_ALLIANCE, u1->faction->locale, "%s %s", alliance_kwd[ALLIANCE_NEW], itoa36(42))); unit_addorder(u1, create_order(K_ALLIANCE, u1->faction->locale, "%s %s", alliance_kwd[ALLIANCE_INVITE], itoa36(u2->faction->no))); unit_addorder(u2, create_order(K_ALLIANCE, u1->faction->locale, "%s %s", alliance_kwd[ALLIANCE_JOIN], itoa36(42))); @@ -109,7 +109,7 @@ static void test_alliance_cmd(CuTest *tc) { CuAssertPtrEquals(tc, al, findalliance(42)); CuAssertTrue(tc, is_allied(u1->faction, u1->faction)); CuAssertPtrEquals(tc, al, u2->faction->alliance); - test_cleanup(); + test_teardown(); } static void test_alliance_limits(CuTest *tc) { @@ -117,9 +117,9 @@ static void test_alliance_limits(CuTest *tc) { struct region *r; test_setup(); - r = test_create_region(0, 0, 0); - u1 = test_create_unit(test_create_faction(0), r); - u2 = test_create_unit(test_create_faction(0), r); + r = test_create_region(0, 0, NULL); + u1 = test_create_unit(test_create_faction(NULL), r); + u2 = test_create_unit(test_create_faction(NULL), r); config_set("rules.limit.alliance", "1"); unit_addorder(u1, create_order(K_ALLIANCE, u1->faction->locale, "%s %s", alliance_kwd[ALLIANCE_NEW], itoa36(42))); @@ -132,7 +132,7 @@ static void test_alliance_limits(CuTest *tc) { CuAssertPtrEquals(tc, 0, f_get_alliance(u2->faction)); CuAssertTrue(tc, !is_allied(u1->faction, u2->faction)); CuAssertPtrNotNull(tc, test_find_messagetype(u2->faction->msgs, "too_many_units_in_alliance")); - test_cleanup(); + test_teardown(); } static void test_alliance_cmd_kick(CuTest *tc) { @@ -142,9 +142,9 @@ static void test_alliance_cmd_kick(CuTest *tc) { test_setup(); al = makealliance(42, "Hodor"); - r = test_create_region(0, 0, 0); - u1 = test_create_unit(test_create_faction(0), r); - u2 = test_create_unit(test_create_faction(0), r); + r = test_create_region(0, 0, NULL); + u1 = test_create_unit(test_create_faction(NULL), r); + u2 = test_create_unit(test_create_faction(NULL), r); setalliance(u1->faction, al); setalliance(u2->faction, al); @@ -153,7 +153,7 @@ static void test_alliance_cmd_kick(CuTest *tc) { alliance_cmd(); CuAssertTrue(tc, !is_allied(u1->faction, u2->faction)); CuAssertPtrEquals(tc, 0, f_get_alliance(u2->faction)); - test_cleanup(); + test_teardown(); } static void test_alliance_cmd_no_invite(CuTest *tc) { @@ -161,9 +161,9 @@ static void test_alliance_cmd_no_invite(CuTest *tc) { struct region *r; test_setup(); - r = test_create_region(0, 0, 0); - u1 = test_create_unit(test_create_faction(0), r); - u2 = test_create_unit(test_create_faction(0), r); + r = test_create_region(0, 0, NULL); + u1 = test_create_unit(test_create_faction(NULL), r); + u2 = test_create_unit(test_create_faction(NULL), r); unit_addorder(u1, create_order(K_ALLIANCE, u1->faction->locale, "%s %s", alliance_kwd[ALLIANCE_NEW], itoa36(42))); unit_addorder(u2, create_order(K_ALLIANCE, u1->faction->locale, "%s %s", alliance_kwd[ALLIANCE_JOIN], itoa36(42))); CuAssertTrue(tc, is_allied(u1->faction, u1->faction)); @@ -173,7 +173,7 @@ static void test_alliance_cmd_no_invite(CuTest *tc) { CuAssertPtrNotNull(tc, f_get_alliance(u1->faction)); CuAssertPtrEquals(tc, 0, f_get_alliance(u2->faction)); CuAssertTrue(tc, !is_allied(u1->faction, u2->faction)); - test_cleanup(); + test_teardown(); } static void test_alliance_cmd_leave(CuTest *tc) { @@ -183,9 +183,9 @@ static void test_alliance_cmd_leave(CuTest *tc) { test_setup(); al = makealliance(42, "Hodor"); - r = test_create_region(0, 0, 0); - u1 = test_create_unit(test_create_faction(0), r); - u2 = test_create_unit(test_create_faction(0), r); + r = test_create_region(0, 0, NULL); + u1 = test_create_unit(test_create_faction(NULL), r); + u2 = test_create_unit(test_create_faction(NULL), r); setalliance(u1->faction, al); setalliance(u2->faction, al); @@ -194,7 +194,7 @@ static void test_alliance_cmd_leave(CuTest *tc) { alliance_cmd(); CuAssertTrue(tc, !is_allied(u1->faction, u2->faction)); CuAssertPtrEquals(tc, 0, f_get_alliance(u1->faction)); - test_cleanup(); + test_teardown(); } static void test_alliance_cmd_transfer(CuTest *tc) { @@ -204,19 +204,18 @@ static void test_alliance_cmd_transfer(CuTest *tc) { test_setup(); al = makealliance(42, "Hodor"); - r = test_create_region(0, 0, 0); - u1 = test_create_unit(test_create_faction(0), r); - u2 = test_create_unit(test_create_faction(0), r); + r = test_create_region(0, 0, NULL); + u1 = test_create_unit(test_create_faction(NULL), r); + u2 = test_create_unit(test_create_faction(NULL), r); setalliance(u1->faction, al); setalliance(u2->faction, al); CuAssertPtrEquals(tc, u1->faction, alliance_get_leader(al)); unit_addorder(u1, create_order(K_ALLIANCE, u1->faction->locale, "%s %s", alliance_kwd[ALLIANCE_TRANSFER], itoa36(u2->faction->no))); alliance_cmd(); CuAssertPtrEquals(tc, u2->faction, alliance_get_leader(al)); - test_cleanup(); + test_teardown(); } - CuSuite *get_alliance_suite(void) { CuSuite *suite = CuSuiteNew(); diff --git a/src/kernel/ally.c b/src/kernel/ally.c index 73f198091..dbb6aff3a 100644 --- a/src/kernel/ally.c +++ b/src/kernel/ally.c @@ -11,6 +11,7 @@ #include "plane.h" #include +#include #include #include @@ -103,7 +104,7 @@ int AllianceAuto(void) const char *str = config_get("alliance.auto"); value = 0; if (str != NULL) { - char *sstr = strdup(str); + char *sstr = str_strdup(str); char *tok = strtok(sstr, " "); while (tok) { value |= ally_flag(tok, -1); @@ -163,7 +164,7 @@ int HelpMask(void) if (config_changed(&config)) { const char *str = config_get("rules.help.mask"); if (str != NULL) { - char *sstr = strdup(str); + char *sstr = str_strdup(str); char *tok = strtok(sstr, " "); while (tok) { rule |= ally_flag(tok, -1); @@ -183,7 +184,7 @@ static int AllianceRestricted(void) const char *str = config_get("alliance.restricted"); int rule = 0; if (str != NULL) { - char *sstr = strdup(str); + char *sstr = str_strdup(str); char *tok = strtok(sstr, " "); while (tok) { rule |= ally_flag(tok, -1); diff --git a/src/kernel/ally.test.c b/src/kernel/ally.test.c index c5c47298f..66542a298 100644 --- a/src/kernel/ally.test.c +++ b/src/kernel/ally.test.c @@ -8,7 +8,7 @@ static void test_ally(CuTest * tc) { ally * al = 0; - struct faction * f1 = test_create_faction(0); + struct faction * f1 = test_create_faction(NULL); ally_add(&al, f1); CuAssertPtrNotNull(tc, al); diff --git a/src/kernel/build.c b/src/kernel/build.c index 1f4e143df..677cf96fc 100644 --- a/src/kernel/build.c +++ b/src/kernel/build.c @@ -16,8 +16,9 @@ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. **/ +#ifdef _MSC_VER #include -#include +#endif #include "build.h" #include "alchemy.h" @@ -34,6 +35,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include #include #include #include @@ -121,11 +123,12 @@ static void destroy_road(unit * u, int nmax, struct order *ord) } road = rroad(r, d); - n = MIN(n, road); + if (n > road) n = road; + if (n != 0) { region *r2 = rconnect(r, d); int willdo = effskill(u, SK_ROAD_BUILDING, 0) * u->number; - willdo = MIN(willdo, n); + if (willdo > n) willdo = n; if (willdo == 0) { /* TODO: error message */ } @@ -161,7 +164,7 @@ int destroy_cmd(unit * u, struct order *ord) return 52; } - init_order(ord); + init_order_depr(ord); s = gettoken(token, sizeof(token)); if (s && *s) { @@ -324,8 +327,9 @@ void build_road(unit * u, int size, direction_t d) return; } - if (size > 0) - left = MIN(size, left); + if (size > 0 && left > size) { + left = size; + } /* baumaximum anhand der rohstoffe */ if (u_race(u) == get_race(RC_STONEGOLEM)) { n = u->number * GOLEM_STONE; @@ -337,7 +341,7 @@ void build_road(unit * u, int size, direction_t d) return; } } - left = MIN(n, left); + if (n < left) left = n; /* n = maximum by skill. try to maximize it */ n = u->number * effsk; @@ -345,7 +349,7 @@ void build_road(unit * u, int size, direction_t d) const resource_type *ring = get_resourcetype(R_RING_OF_NIMBLEFINGER); item *itm = ring ? *i_find(&u->items, ring->itype) : 0; if (itm != NULL && itm->number > 0) { - int rings = MIN(u->number, itm->number); + int rings = (u->number < itm->number) ? u->number : itm->number; n = n * ((roqf_factor() - 1) * rings + u->number) / u->number; } } @@ -353,15 +357,15 @@ void build_road(unit * u, int size, direction_t d) int dm = get_effect(u, oldpotiontype[P_DOMORE]); if (dm != 0) { int todo = (left - n + effsk - 1) / effsk; - todo = MIN(todo, u->number); - dm = MIN(dm, todo); + if (todo > u->number) todo = u->number; + if (dm > todo) dm = todo; change_effect(u, oldpotiontype[P_DOMORE], -dm); n += dm * effsk; } /* Auswirkung Schaffenstrunk */ } /* make minimum of possible and available: */ - n = MIN(left, n); + if (n > left) n = left; /* n is now modified by several special effects, so we have to * minimize it again to make sure the road will not grow beyond @@ -378,7 +382,7 @@ void build_road(unit * u, int size, direction_t d) else { use_pooled(u, get_resourcetype(R_STONE), GET_DEFAULT, n); /* Nur soviel PRODUCEEXP wie auch tatsaechlich gemacht wurde */ - produceexp(u, SK_ROAD_BUILDING, MIN(n, u->number)); + produceexp(u, SK_ROAD_BUILDING, (n < u->number) ? n : u->number); } ADDMSG(&u->faction->msgs, msg_message("buildroad", "region unit size", r, u, n)); @@ -405,7 +409,7 @@ static int required(int size, int msize, int maxneed) static int matmod(const unit * u, const resource_type * rtype, int value) { if (rtype->modifiers) { - variant save = frac_make(1, 1); + variant save = frac_one; const struct building_type *btype = NULL; const struct race *rc = u_race(u); resource_mod *mod; @@ -533,7 +537,7 @@ int build(unit * u, const construction * ctype, int completed, int want, int ski if (dm != 0) { /* Auswirkung Schaffenstrunk */ - dm = MIN(dm, u->number); + if (dm > u->number) dm = u->number; change_effect(u, oldpotiontype[P_DOMORE], -dm); skills += dm * effsk; } @@ -592,7 +596,7 @@ int build(unit * u, const construction * ctype, int completed, int want, int ski item *itm = ring ? *i_find(&u->items, ring->itype) : 0; int i = itm ? itm->number : 0; if (i > 0) { - int rings = MIN(u->number, i); + int rings = (u->number < i) ? u->number : i; n = n * ((roqf_factor() - 1) * rings + u->number) / u->number; } } @@ -600,7 +604,8 @@ int build(unit * u, const construction * ctype, int completed, int want, int ski if (want < n) n = want; if (con->maxsize > 0) { - n = MIN(con->maxsize - completed, n); + int req = con->maxsize - completed; + if (req < n) n = req; if (con->improvement == NULL) { want = n; } @@ -623,7 +628,7 @@ int build(unit * u, const construction * ctype, int completed, int want, int ski completed = completed + n; } /* Nur soviel PRODUCEEXP wie auch tatsaechlich gemacht wurde */ - produceexp(u, ctype->skill, MIN(made, u->number)); + produceexp(u, ctype->skill, (made < u->number) ? made : u->number); return made; } @@ -667,8 +672,10 @@ int maxbuild(const unit * u, const construction * cons) if (have < need) { return 0; } - else - maximum = MIN(maximum, have / need); + else { + int b = have / need; + if (maximum > b) maximum = b; + } } return maximum; } @@ -877,7 +884,8 @@ static void build_ship(unit * u, ship * sh, int want) } if (sh->damage && can) { - int repair = MIN(sh->damage, can * DAMAGE_SCALE); + int repair = can * DAMAGE_SCALE; + if (repair > sh->damage) repair = sh->damage; n += repair / DAMAGE_SCALE; if (repair % DAMAGE_SCALE) ++n; @@ -920,10 +928,9 @@ order * ord) cmistake(u, ord, 88, MSG_PRODUCE); return; } - if (want > 0) - want = MIN(want, msize); - else + if (want <= 0 || want > msize) { want = msize; + } sh = new_ship(newtype, r, u->faction->locale); @@ -979,10 +986,9 @@ void continue_ship(unit * u, int want) cmistake(u, u->thisorder, 88, MSG_PRODUCE); return; } - if (want > 0) - want = MIN(want, msize); - else + if (want <= 0 || want > msize) { want = msize; + } build_ship(u, sh, want); } diff --git a/src/kernel/build.test.c b/src/kernel/build.test.c index 8cd408b09..ece28f4eb 100644 --- a/src/kernel/build.test.c +++ b/src/kernel/build.test.c @@ -29,13 +29,14 @@ typedef struct build_fixture { } build_fixture; static unit * setup_build(build_fixture *bf) { - test_cleanup(); + test_setup(); + test_inject_messagetypes(); init_resources(); test_create_itemtype("stone"); test_create_buildingtype("castle"); bf->rc = test_create_race("human"); - bf->r = test_create_region(0, 0, 0); + bf->r = test_create_region(0, 0, NULL); bf->f = test_create_faction(bf->rc); assert(bf->rc && bf->f && bf->r); bf->u = test_create_unit(bf->f, bf->r); @@ -53,7 +54,7 @@ static unit * setup_build(build_fixture *bf) { static void teardown_build(build_fixture *bf) { free(bf->cons.materials); - test_cleanup(); + test_teardown(); } static void test_build_requires_materials(CuTest *tc) { @@ -160,12 +161,12 @@ static void test_build_with_ring(CuTest *tc) { static void test_build_with_potion(CuTest *tc) { build_fixture bf = { 0 }; unit *u; - const potion_type *ptype; + const item_type *ptype; const struct resource_type *rtype; u = setup_build(&bf); rtype = bf.cons.materials[0].rtype; - oldpotiontype[P_DOMORE] = ptype = new_potiontype(it_get_or_create(rt_get_or_create("hodor")), 1); + oldpotiontype[P_DOMORE] = ptype = it_get_or_create(rt_get_or_create("hodor")); assert(rtype && ptype); i_change(&u->items, rtype->itype, 20); @@ -207,7 +208,7 @@ static void test_build_building_with_golem(CuTest *tc) { const building_type *btype; u = setup_build(&bf); - bf.rc->flags |= RCF_STONEGOLEM; + bf.rc->ec_flags |= ECF_STONEGOLEM; btype = bt_find("castle"); assert(btype); assert(btype->construction); @@ -254,12 +255,12 @@ static void test_build_destroy_road(CuTest *tc) order *ord; message *m; - test_cleanup(); - mt_register(mt_new_va("destroy_road", "unit:unit", "from:region", "to:region", 0)); + test_setup(); + mt_register(mt_new_va("destroy_road", "unit:unit", "from:region", "to:region", NULL)); r2 = test_create_region(1, 0, 0); - r = test_create_region(0, 0, 0); + r = test_create_region(0, 0, NULL); rsetroad(r, D_EAST, 100); - u = test_create_unit(f = test_create_faction(0), r); + u = test_create_unit(f = test_create_faction(NULL), r); u->orders = ord = create_order(K_DESTROY, f->locale, "%s %s", LOC(f->locale, parameters[P_ROAD]), LOC(f->locale, directions[D_EAST])); CuAssertIntEquals(tc, 0, destroy_cmd(u, ord)); @@ -282,7 +283,7 @@ static void test_build_destroy_road(CuTest *tc) set_level(u, SK_ROAD_BUILDING, 2); CuAssertIntEquals(tc, 0, destroy_cmd(u, ord)); CuAssertIntEquals(tc, 87, rroad(r, D_EAST)); - test_cleanup(); + test_teardown(); } unit *test_create_guard(region *r, faction *f, race *rc) { @@ -308,12 +309,13 @@ static void test_build_destroy_road_guard(CuTest *tc) unit *u, *ug; order *ord; - test_cleanup(); + test_setup(); + test_inject_messagetypes(); test_create_region(1, 0, 0); - r = test_create_region(0, 0, 0); + r = test_create_region(0, 0, NULL); rsetroad(r, D_EAST, 100); ug = test_create_guard(r, 0, 0); - u = test_create_unit(f = test_create_faction(0), r); + u = test_create_unit(f = test_create_faction(NULL), r); u->orders = ord = create_order(K_DESTROY, f->locale, "%s %s", LOC(f->locale, parameters[P_ROAD]), LOC(f->locale, directions[D_EAST])); set_level(u, SK_ROAD_BUILDING, 1); @@ -330,7 +332,7 @@ static void test_build_destroy_road_guard(CuTest *tc) CuAssertPtrEquals(tc, NULL, test_find_messagetype(f->msgs, "error70")); CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "destroy_road")); - test_cleanup(); + test_teardown(); } static void test_build_destroy_road_limit(CuTest *tc) @@ -340,11 +342,12 @@ static void test_build_destroy_road_limit(CuTest *tc) unit *u; order *ord; - test_cleanup(); + test_setup(); + test_inject_messagetypes(); test_create_region(1, 0, 0); - r = test_create_region(0, 0, 0); + r = test_create_region(0, 0, NULL); rsetroad(r, D_EAST, 100); - u = test_create_unit(f = test_create_faction(0), r); + u = test_create_unit(f = test_create_faction(NULL), r); u->orders = ord = create_order(K_DESTROY, f->locale, "1 %s %s", LOC(f->locale, parameters[P_ROAD]), LOC(f->locale, directions[D_EAST])); set_level(u, SK_ROAD_BUILDING, 1); @@ -357,7 +360,7 @@ static void test_build_destroy_road_limit(CuTest *tc) CuAssertIntEquals(tc, 98, rroad(r, D_EAST)); CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "destroy_road")); - test_cleanup(); + test_teardown(); } static void test_build_destroy_cmd(CuTest *tc) { @@ -365,11 +368,11 @@ static void test_build_destroy_cmd(CuTest *tc) { faction *f; test_setup(); - u = test_create_unit(f = test_create_faction(0), test_create_region(0, 0, 0)); + u = test_create_unit(f = test_create_faction(NULL), test_create_region(0, 0, NULL)); u->thisorder = create_order(K_DESTROY, f->locale, NULL); CuAssertIntEquals(tc, 138, destroy_cmd(u, u->thisorder)); CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error138")); - test_cleanup(); + test_teardown(); } static void test_build_roqf_factor(CuTest *tc) { @@ -377,7 +380,7 @@ static void test_build_roqf_factor(CuTest *tc) { CuAssertIntEquals(tc, 10, roqf_factor()); config_set("rules.economy.roqf", "50"); CuAssertIntEquals(tc, 50, roqf_factor()); - test_cleanup(); + test_teardown(); } CuSuite *get_build_suite(void) diff --git a/src/kernel/building.c b/src/kernel/building.c index 57b8a91e2..35efa8579 100644 --- a/src/kernel/building.c +++ b/src/kernel/building.c @@ -38,13 +38,13 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* util includes */ #include #include -#include #include #include #include #include #include #include +#include #include #include @@ -54,6 +54,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* libc includes */ #include #include +#include #include #include @@ -134,7 +135,7 @@ building_type *bt_get_or_create(const char *name) building_type *btype = bt_find_i(name); if (btype == NULL) { btype = calloc(sizeof(building_type), 1); - btype->_name = strdup(name); + btype->_name = str_strdup(name); btype->auraregen = 1.0; btype->maxsize = -1; btype->capacity = 1; @@ -372,8 +373,8 @@ building *new_building(const struct building_type * btype, region * r, bname = parameters[P_GEBAEUDE]; } assert(bname); - slprintf(buffer, sizeof(buffer), "%s %s", bname, itoa36(b->no)); - b->name = strdup(bname); + snprintf(buffer, sizeof(buffer), "%s %s", bname, itoa36(b->no)); + b->name = str_strdup(bname); return b; } @@ -385,14 +386,16 @@ static building *deleted_buildings; void remove_building(building ** blist, building * b) { unit *u; - const struct building_type *bt_caravan, *bt_dam, *bt_tunnel; + static const struct building_type *bt_caravan, *bt_dam, *bt_tunnel; + static int btypes; assert(bfindhash(b->no)); - bt_caravan = bt_find("caravan"); - bt_dam = bt_find("dam"); - bt_tunnel = bt_find("tunnel"); - + if (bt_changed(&btypes)) { + bt_caravan = bt_find("caravan"); + bt_dam = bt_find("dam"); + bt_tunnel = bt_find("tunnel"); + } handle_event(b->attribs, "destroy", b); for (u = b->region->units; u; u = u->next) { if (u->building == b) leave(u, true); @@ -404,7 +407,6 @@ void remove_building(building ** blist, building * b) /* Falls Karawanserei, Damm oder Tunnel einst�rzen, wird die schon * gebaute Strasse zur Haelfte vernichtet */ - /* TODO: caravan, tunnel, dam modularization ? is_building_type ? */ if (b->type == bt_caravan || b->type == bt_dam || b->type == bt_tunnel) { region *r = b->region; int d; @@ -489,7 +491,7 @@ int bt_effsize(const building_type * btype, const building * b, int bsize) const char *write_buildingname(const building * b, char *ibuf, size_t size) { - slprintf(ibuf, size, "%s (%s)", b->name, itoa36(b->no)); + snprintf(ibuf, size, "%s (%s)", b->name, itoa36(b->no)); return ibuf; } @@ -499,7 +501,7 @@ const char *buildingname(const building * b) static name idbuf[8]; static int nextbuf = 0; char *ibuf = idbuf[(++nextbuf) % 8]; - return write_buildingname(b, ibuf, sizeof(name)); + return write_buildingname(b, ibuf, sizeof(idbuf[0])); } void building_set_owner(struct unit * owner) @@ -568,7 +570,7 @@ void building_setname(building * self, const char *name) { free(self->name); if (name) - self->name = strdup(name); + self->name = str_strdup(name); else self->name = NULL; } @@ -774,22 +776,11 @@ int cmp_wage(const struct building *b, const building * a) return -1; } -bool is_owner_building(const struct building * b) -{ - region *r = b->region; - if (b->type->taxes && r->land && r->land->ownership) { - unit *u = building_owner(b); - return u && u->faction == r->land->ownership->owner; - } - return false; -} - int building_taxes(const building *b) { assert(b); return b->type->taxes; } - int cmp_taxes(const building * b, const building * a) { faction *f = region_get_owner(b->region); diff --git a/src/kernel/building.h b/src/kernel/building.h index af29c324b..e162e041f 100644 --- a/src/kernel/building.h +++ b/src/kernel/building.h @@ -71,7 +71,6 @@ extern "C" { } building_type; extern struct selist *buildingtypes; - extern struct attrib_type at_building_action; extern struct attrib_type at_building_generic_type; int cmp_castle_size(const struct building *b, const struct building *a); diff --git a/src/kernel/building.test.c b/src/kernel/building.test.c index e19d074da..8d5b86dc9 100644 --- a/src/kernel/building.test.c +++ b/src/kernel/building.test.c @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -19,7 +20,7 @@ static void test_register_building(CuTest * tc) building_type *btype; int cache = 0; - test_cleanup(); + test_setup(); CuAssertIntEquals(tc, true, bt_changed(&cache)); CuAssertIntEquals(tc, false, bt_changed(&cache)); @@ -30,7 +31,7 @@ static void test_register_building(CuTest * tc) free_buildingtypes(); CuAssertIntEquals(tc, true, bt_changed(&cache)); - test_cleanup(); + test_teardown(); } static void test_building_set_owner(CuTest * tc) @@ -55,7 +56,7 @@ static void test_building_set_owner(CuTest * tc) CuAssertPtrEquals(tc, u1, building_owner(bld)); building_set_owner(u2); CuAssertPtrEquals(tc, u2, building_owner(bld)); - test_cleanup(); + test_teardown(); } static void test_buildingowner_goes_to_next_when_empty(CuTest * tc) @@ -81,7 +82,7 @@ static void test_buildingowner_goes_to_next_when_empty(CuTest * tc) CuAssertPtrEquals(tc, u, building_owner(bld)); u->number = 0; CuAssertPtrEquals(tc, u2, building_owner(bld)); - test_cleanup(); + test_teardown(); } static void test_buildingowner_goes_to_other_when_empty(CuTest * tc) @@ -108,7 +109,7 @@ static void test_buildingowner_goes_to_other_when_empty(CuTest * tc) CuAssertPtrEquals(tc, u, building_owner(bld)); u->number = 0; CuAssertPtrEquals(tc, u2, building_owner(bld)); - test_cleanup(); + test_teardown(); } static void test_buildingowner_goes_to_same_faction_when_empty(CuTest * tc) @@ -139,7 +140,7 @@ static void test_buildingowner_goes_to_same_faction_when_empty(CuTest * tc) CuAssertPtrEquals(tc, u3, building_owner(bld)); u3->number = 0; CuAssertPtrEquals(tc, u2, building_owner(bld)); - test_cleanup(); + test_teardown(); } static void test_buildingowner_goes_to_next_after_leave(CuTest * tc) @@ -164,7 +165,7 @@ static void test_buildingowner_goes_to_next_after_leave(CuTest * tc) CuAssertPtrEquals(tc, u, building_owner(bld)); leave_building(u); CuAssertPtrEquals(tc, u2, building_owner(bld)); - test_cleanup(); + test_teardown(); } static void test_buildingowner_goes_to_other_after_leave(CuTest * tc) @@ -190,7 +191,7 @@ static void test_buildingowner_goes_to_other_after_leave(CuTest * tc) CuAssertPtrEquals(tc, u, building_owner(bld)); leave_building(u); CuAssertPtrEquals(tc, u2, building_owner(bld)); - test_cleanup(); + test_teardown(); } static void test_buildingowner_goes_to_same_faction_after_leave(CuTest * tc) @@ -223,7 +224,7 @@ static void test_buildingowner_goes_to_same_faction_after_leave(CuTest * tc) CuAssertPtrEquals(tc, u2, building_owner(bld)); leave_building(u2); CuAssertPtrEquals(tc, 0, building_owner(bld)); - test_cleanup(); + test_teardown(); } static void test_buildingowner_resets_when_empty(CuTest * tc) @@ -249,7 +250,7 @@ static void test_buildingowner_resets_when_empty(CuTest * tc) CuAssertPtrEquals(tc, 0, building_owner(bld)); u->number = 1; CuAssertPtrEquals(tc, u, building_owner(bld)); - test_cleanup(); + test_teardown(); } void test_buildingowner_goes_to_empty_unit_after_leave(CuTest * tc) @@ -282,12 +283,13 @@ void test_buildingowner_goes_to_empty_unit_after_leave(CuTest * tc) CuAssertPtrEquals(tc, 0, building_owner(bld)); u2->number = 1; CuAssertPtrEquals(tc, u2, building_owner(bld)); - test_cleanup(); + test_teardown(); } static void test_btype_defaults(CuTest *tc) { building_type * btype; - test_cleanup(); + + test_setup(); btype = bt_get_or_create("hodor"); CuAssertPtrNotNull(tc, btype); @@ -303,7 +305,7 @@ static void test_btype_defaults(CuTest *tc) { CuAssertIntEquals(tc, 0, btype->magresbonus); CuAssertIntEquals(tc, 0, btype->fumblebonus); CuAssertIntEquals(tc, 0, btype->flags); - test_cleanup(); + test_teardown(); } static void test_buildingtype_exists(CuTest * tc) @@ -341,6 +343,7 @@ static void test_buildingtype_exists(CuTest * tc) CuAssertTrue(tc, buildingtype_exists(r, btype, true)); freset(b, BLD_MAINTAINED); CuAssertTrue(tc, !buildingtype_exists(r, btype, true)); + test_teardown(); } static void test_active_building(CuTest *tc) { @@ -349,12 +352,12 @@ static void test_active_building(CuTest *tc) { unit *u; building_type *btype; - test_cleanup(); + test_setup(); btype = test_create_buildingtype("castle"); assert(btype && btype->maxsize == -1); - b = test_create_building(r = test_create_region(0, 0, 0), btype); - u = test_create_unit(test_create_faction(0), r); + b = test_create_building(r = test_create_region(0, 0, NULL), btype); + u = test_create_unit(test_create_faction(NULL), r); CuAssertIntEquals(tc, false, building_is_active(b)); CuAssertPtrEquals(tc, NULL, active_building(u, btype)); @@ -375,17 +378,17 @@ static void test_active_building(CuTest *tc) { b->flags &= ~BLD_MAINTAINED; CuAssertIntEquals(tc, false, building_is_active(b)); CuAssertPtrEquals(tc, NULL, active_building(u, btype)); - test_cleanup(); + test_teardown(); } static void test_safe_building(CuTest *tc) { building_type *btype; unit *u1, *u2; - test_cleanup(); + test_setup(); btype = test_create_buildingtype("castle"); - u1 = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); - u2 = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + u1 = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); + u2 = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); CuAssertIntEquals(tc, false, in_safe_building(u1, u2)); u1->building = test_create_building(u1->region, btype); CuAssertIntEquals(tc, false, in_safe_building(u1, u2)); @@ -397,7 +400,7 @@ static void test_safe_building(CuTest *tc) { CuAssertIntEquals(tc, false, in_safe_building(u1, u2)); u1->building->size = 3; CuAssertIntEquals(tc, false, in_safe_building(u1, u2)); - test_cleanup(); + test_teardown(); } static void test_building_type(CuTest *tc) { @@ -406,7 +409,7 @@ static void test_building_type(CuTest *tc) { btype = test_create_buildingtype("house"); CuAssertIntEquals(tc, true, is_building_type(btype, "house")); CuAssertIntEquals(tc, false, is_building_type(btype, "castle")); - test_cleanup(); + test_teardown(); } static void test_cmp_castle_size(CuTest *tc) { @@ -415,19 +418,19 @@ static void test_cmp_castle_size(CuTest *tc) { unit *u1, *u2; test_setup(); - r = test_create_region(0, 0, 0); + r = test_create_region(0, 0, NULL); b1 = test_create_building(r, NULL); b2 = test_create_building(r, NULL); - u1 = test_create_unit(test_create_faction(0), r); + u1 = test_create_unit(test_create_faction(NULL), r); u_set_building(u1, b1); - u2 = test_create_unit(test_create_faction(0), r); + u2 = test_create_unit(test_create_faction(NULL), r); u_set_building(u2, b2); b1->size = 5; b2->size = 10; CuAssertTrue(tc, cmp_castle_size(b1, b2) < 0); CuAssertTrue(tc, cmp_castle_size(b2, b1) > 0); CuAssertTrue(tc, cmp_castle_size(b1, b1) == 0); - test_cleanup(); + test_teardown(); } static void test_cmp_wage(CuTest *tc) { @@ -438,7 +441,7 @@ static void test_cmp_wage(CuTest *tc) { test_setup(); btype = test_create_buildingtype("castle"); btype->taxes = 100; - r = test_create_region(0, 0, 0); + r = test_create_region(0, 0, NULL); b1 = test_create_building(r, btype); b2 = test_create_building(r, btype); b1->size = 5; @@ -447,7 +450,7 @@ static void test_cmp_wage(CuTest *tc) { CuAssertTrue(tc, cmp_wage(b1, b2) < 0); CuAssertTrue(tc, cmp_wage(b2, b1) > 0); CuAssertTrue(tc, cmp_wage(b1, b1) == 0); - test_cleanup(); + test_teardown(); } static void test_cmp_taxes(CuTest *tc) { @@ -459,20 +462,20 @@ static void test_cmp_taxes(CuTest *tc) { test_setup(); btype = test_create_buildingtype("castle"); btype->taxes = 100; - r = test_create_region(0, 0, 0); + r = test_create_region(0, 0, NULL); b1 = test_create_building(r, btype); b2 = test_create_building(r, btype); b1->size = 5; b2->size = 10; - u1 = test_create_unit(test_create_faction(0), r); + u1 = test_create_unit(test_create_faction(NULL), r); u_set_building(u1, b1); - u2 = test_create_unit(test_create_faction(0), r); + u2 = test_create_unit(test_create_faction(NULL), r); u_set_building(u2, b2); CuAssertPtrEquals(tc, b2, largestbuilding(r, cmp_taxes, false)); CuAssertTrue(tc, cmp_taxes(b1, b2) < 0); CuAssertTrue(tc, cmp_taxes(b2, b1) > 0); CuAssertTrue(tc, cmp_taxes(b1, b1) == 0); - test_cleanup(); + test_teardown(); } static void test_cmp_current_owner(CuTest *tc) { @@ -483,7 +486,7 @@ static void test_cmp_current_owner(CuTest *tc) { test_setup(); config_set("rules.region_owners", "1"); - r = test_create_region(0, 0, 0); + r = test_create_region(0, 0, NULL); btype = test_create_buildingtype("watch"); btype->construction->maxsize = 1; btype->taxes = 200; @@ -496,16 +499,16 @@ static void test_cmp_current_owner(CuTest *tc) { CuAssertIntEquals(tc, 1, buildingeffsize(b1, false)); b2->size = 1; CuAssertIntEquals(tc, 1, buildingeffsize(b2, false)); - u1 = test_create_unit(test_create_faction(0), r); + u1 = test_create_unit(test_create_faction(NULL), r); u_set_building(u1, b1); - u2 = test_create_unit(test_create_faction(0), r); + u2 = test_create_unit(test_create_faction(NULL), r); u_set_building(u2, b2); region_set_owner(r, u1->faction, turn); CuAssertPtrEquals(tc, b1, largestbuilding(r, cmp_current_owner, false)); CuAssertTrue(tc, cmp_current_owner(b2, b1) < 0); CuAssertTrue(tc, cmp_current_owner(b1, b2) > 0); CuAssertTrue(tc, cmp_current_owner(b1, b1) == 0); - test_cleanup(); + test_teardown(); } static void test_building_effsize(CuTest *tc) { @@ -530,7 +533,7 @@ static void test_building_effsize(CuTest *tc) { CuAssertIntEquals(tc, 2, buildingeffsize(b, false)); b->size = 20; CuAssertIntEquals(tc, 2, buildingeffsize(b, false)); - test_cleanup(); + test_teardown(); } static int cmp_size(const building *lhs, const building *rhs) { @@ -553,7 +556,7 @@ static void test_largestbuilding(CuTest *tc) { CuAssertPtrEquals(tc, b1, largestbuilding(r, cmp_size, false)); b2->size = 3; CuAssertPtrEquals(tc, b2, largestbuilding(r, cmp_size, false)); - test_cleanup(); + test_teardown(); } static void test_buildingtype(CuTest *tc) { @@ -562,12 +565,12 @@ static void test_buildingtype(CuTest *tc) { btype = test_create_buildingtype("hodor"); CuAssertPtrNotNull(tc, btype->construction); CuAssertStrEquals(tc, "hodor", buildingtype(btype, NULL, 1)); - btype->construction->name = strdup("castle"); + btype->construction->name = str_strdup("castle"); CuAssertStrEquals(tc, "castle", buildingtype(btype, NULL, 1)); btype = bt_get_or_create("portal"); CuAssertPtrEquals(tc, NULL, btype->construction); CuAssertStrEquals(tc, "portal", buildingtype(btype, NULL, 1)); - test_cleanup(); + test_teardown(); } static void test_buildingcapacity(CuTest *tc) { @@ -587,7 +590,7 @@ static void test_buildingcapacity(CuTest *tc) { btype->capacity = -1; CuAssertTrue(tc, building_finished(b)); CuAssertIntEquals(tc, btype->maxcapacity, buildingcapacity(b)); - test_cleanup(); + test_teardown(); } CuSuite *get_building_suite(void) diff --git a/src/kernel/command.c b/src/kernel/command.c index 912f21f7d..8b2a7e5e8 100644 --- a/src/kernel/command.c +++ b/src/kernel/command.c @@ -14,6 +14,7 @@ #include #include "command.h" +#include #include #include @@ -104,10 +105,10 @@ static int do_command_i(const struct tnode *keys, struct unit *u, struct order * void do_command(const struct tnode *keys, struct unit *u, struct order *ord) { - init_order(ord); + init_order_depr(ord); if (do_command_i(keys, u, ord) != E_TOK_SUCCESS) { char cmd[ORDERSIZE]; - get_command(ord, cmd, sizeof(cmd)); + get_command(ord, u->faction->locale, cmd, sizeof(cmd)); log_warning("%s failed command '%s'\n", unitname(u), cmd); } } diff --git a/src/kernel/command.test.c b/src/kernel/command.test.c index 25e75fdc3..d173474f2 100644 --- a/src/kernel/command.test.c +++ b/src/kernel/command.test.c @@ -32,7 +32,7 @@ static void test_command(CuTest * tc) { struct locale * loc; unit *u; - test_cleanup(); + test_setup(); loc = test_create_locale(); st = stree_create(); CuAssertPtrNotNull(tc, st); @@ -43,12 +43,12 @@ static void test_command(CuTest * tc) { stree_add(st, "six", parser_six); CuAssertPtrNotNull(tc, st->root); CuAssertPtrEquals(tc, st->root, stree_find(st, loc)); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); u->thisorder = create_order(K_ALLIANCE, loc, "two"); do_command(st->root, u, u->thisorder); CuAssertIntEquals(tc, u->number, 2); stree_free(st); - test_cleanup(); + test_teardown(); } CuSuite *get_command_suite(void) diff --git a/src/kernel/config.c b/src/kernel/config.c index 566b9fc88..9a5ba0104 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -16,8 +16,11 @@ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. **/ +#ifdef _MSC_VER #include -#include +#endif + +#include "config.h" /* kernel includes */ #include "alliance.h" @@ -48,23 +51,21 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "types.h" #include "unit.h" - -#include -#include - /* util includes */ #include #include -#include #include #include #include #include #include #include +#include #include +#include #include #include +#include #include #include #include @@ -73,11 +74,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "guard.h" #include "prefix.h" -#ifdef USE_LIBXML2 /* libxml includes */ #include #include -#endif /* external libraries */ #include @@ -91,11 +90,14 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include -#include +#ifdef WIN32 +#include +#else +#include +#endif struct settings global; -bool lomem = false; int turn = 0; const char *parameters[MAXPARAMS] = { @@ -261,15 +263,6 @@ param_t getparam(const struct locale * lang) return s ? findparam(s, lang) : NOPARAM; } -unit *getnewunit(const region * r, const faction * f) -{ - int n; - n = getid(); - - return findnewunit(r, f, n); -} - - /* -- Erschaffung neuer Einheiten ------------------------------ */ static const char *forbidden[] = { "t", "te", "tem", "temp", NULL }; @@ -393,7 +386,7 @@ static void init_magic(struct locale *lang) str = "gwyrrd illaun draig cerddor tybied"; } - sstr = strdup(str); + sstr = str_strdup(str); tok = strtok(sstr, " "); while (tok) { variant var; @@ -500,7 +493,7 @@ int check_param(const struct param *p, const char *key, const char *searchvalue) if (!value) { return 0; } - p_value = strdup(value); + p_value = str_strdup(value); v = strtok(p_value, " ,;"); while (v != NULL) { @@ -527,34 +520,16 @@ void set_basepath(const char *path) g_basedir = path; } -#ifdef WIN32 -#define PATH_DELIM '\\' -#else -#define PATH_DELIM '/' -#endif - char * join_path(const char *p1, const char *p2, char *dst, size_t len) { - size_t sz; - assert(p1 && p2); - assert(p2 != dst); - if (dst == p1) { - sz = strlen(p1); - } - else { - sz = strlcpy(dst, p1, len); - } - assert(sz < len); - dst[sz++] = PATH_DELIM; - strlcpy(dst + sz, p2, len - sz); - return dst; + return path_join(p1, p2, dst, len); } static const char * relpath(char *buf, size_t sz, const char *path) { if (g_basedir) { - join_path(g_basedir, path, buf, sz); + path_join(g_basedir, path, buf, sz); } else { - strlcpy(buf, path, sz); + str_strlcpy(buf, path, sz); } return buf; } @@ -587,14 +562,23 @@ void set_reportpath(const char *path) g_reportdir = path; } +static int sys_mkdir(const char *path, int mode) { +#ifdef WIN32 + UNUSED_ARG(mode); + return _mkdir(path); +#else + return mkdir(path, mode); +#endif +} + int create_directories(void) { int err; - err = mkdir(datapath(), 0777); + err = sys_mkdir(datapath(), 0777); if (err) { if (errno == EEXIST) errno = 0; else return err; } - err = mkdir(reportpath(), 0777); + err = sys_mkdir(reportpath(), 0777); if (err && errno == EEXIST) { errno = 0; } @@ -612,9 +596,7 @@ void kernel_done(void) /* calling this function releases memory assigned to static variables, etc. * calling it is optional, e.g. a release server will most likely not do it. */ -#ifdef USE_LIBXML2 xml_done(); -#endif attrib_done(); item_done(); message_done(); diff --git a/src/kernel/config.h b/src/kernel/config.h index 4cf0650ff..e0ad682c6 100644 --- a/src/kernel/config.h +++ b/src/kernel/config.h @@ -141,7 +141,6 @@ extern "C" { extern const char *parameters[]; extern settings global; - extern bool lomem; /* save memory */ extern int turn; #ifdef __cplusplus diff --git a/src/kernel/config.test.c b/src/kernel/config.test.c index ac35b85a3..7a2097ce4 100644 --- a/src/kernel/config.test.c +++ b/src/kernel/config.test.c @@ -27,37 +27,37 @@ static void test_read_unitid(CuTest *tc) { lang = test_create_locale(); /* note that the english order is FIGHT, not COMBAT, so this is a poor example */ t_plain = test_create_terrain("plain", LAND_REGION); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, t_plain)); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, t_plain)); a = a_add(&u->attribs, a_new(&at_alias)); a->data.i = atoi36("42"); /* this unit is also TEMP 42 */ ord = create_order(K_GIVE, lang, "TEMP 42"); - init_order(ord); + init_order_depr(ord); CuAssertIntEquals(tc, u->no, read_unitid(u->faction, u->region)); free_order(ord); ord = create_order(K_GIVE, lang, "8"); - init_order(ord); + init_order_depr(ord); CuAssertIntEquals(tc, 8, read_unitid(u->faction, u->region)); free_order(ord); ord = create_order(K_GIVE, lang, ""); - init_order(ord); + init_order_depr(ord); CuAssertIntEquals(tc, -1, read_unitid(u->faction, u->region)); free_order(ord); ord = create_order(K_GIVE, lang, "TEMP"); - init_order(ord); + init_order_depr(ord); CuAssertIntEquals(tc, -1, read_unitid(u->faction, u->region)); free_order(ord); /* bug https://bugs.eressea.de/view.php?id=1685 */ ord = create_order(K_GIVE, lang, "##"); - init_order(ord); + init_order_depr(ord); CuAssertIntEquals(tc, -1, read_unitid(u->faction, u->region)); free_order(ord); - test_cleanup(); + test_teardown(); } static void test_getunit(CuTest *tc) { @@ -72,53 +72,53 @@ static void test_getunit(CuTest *tc) { lang = test_create_locale(); /* note that the english order is FIGHT, not COMBAT, so this is a poor example */ t_plain = test_create_terrain("plain", LAND_REGION); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, t_plain)); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, t_plain)); a = a_add(&u->attribs, a_new(&at_alias)); a->data.i = atoi36("42"); /* this unit is also TEMP 42 */ r = test_create_region(1, 0, t_plain); ord = create_order(K_GIVE, lang, itoa36(u->no)); - init_order(ord); + init_order_depr(ord); CuAssertIntEquals(tc, GET_UNIT, getunit(u->region, u->faction, &u2)); CuAssertPtrEquals(tc, u, u2); - init_order(ord); + init_order_depr(ord); CuAssertIntEquals(tc, GET_NOTFOUND, getunit(r, u->faction, &u2)); CuAssertPtrEquals(tc, NULL, u2); free_order(ord); ord = create_order(K_GIVE, lang, itoa36(u->no + 1)); - init_order(ord); + init_order_depr(ord); CuAssertIntEquals(tc, GET_NOTFOUND, getunit(u->region, u->faction, &u2)); CuAssertPtrEquals(tc, NULL, u2); free_order(ord); ord = create_order(K_GIVE, lang, "0"); - init_order(ord); + init_order_depr(ord); CuAssertIntEquals(tc, GET_PEASANTS, getunit(u->region, u->faction, &u2)); CuAssertPtrEquals(tc, NULL, u2); free_order(ord); /* bug https://bugs.eressea.de/view.php?id=1685 */ ord = create_order(K_GIVE, lang, "TEMP ##"); - init_order(ord); + init_order_depr(ord); CuAssertIntEquals(tc, GET_NOTFOUND, getunit(u->region, u->faction, &u2)); CuAssertPtrEquals(tc, NULL, u2); free_order(ord); /* bug https://bugs.eressea.de/view.php?id=1685 */ ord = create_order(K_GIVE, lang, "##"); - init_order(ord); + init_order_depr(ord); CuAssertIntEquals(tc, GET_NOTFOUND, getunit(u->region, u->faction, &u2)); CuAssertPtrEquals(tc, NULL, u2); free_order(ord); ord = create_order(K_GIVE, lang, "TEMP 42"); - init_order(ord); + init_order_depr(ord); CuAssertIntEquals(tc, GET_UNIT, getunit(u->region, u->faction, &u2)); CuAssertPtrEquals(tc, u, u2); free_order(ord); - test_cleanup(); + test_teardown(); } static void test_get_set_param(CuTest * tc) @@ -135,7 +135,7 @@ static void test_get_set_param(CuTest * tc) set_param(&par, "bar", NULL); CuAssertPtrEquals(tc, NULL, (void *)get_param(par, "bar")); free_params(&par); - test_cleanup(); + test_teardown(); } static void test_param_int(CuTest * tc) @@ -148,7 +148,7 @@ static void test_param_int(CuTest * tc) CuAssertIntEquals(tc, 23, get_param_int(par, "foo", 0)); CuAssertIntEquals(tc, 42, get_param_int(par, "bar", 0)); free_params(&par); - test_cleanup(); + test_teardown(); } static void test_param_flt(CuTest * tc) @@ -161,7 +161,7 @@ static void test_param_flt(CuTest * tc) CuAssertDblEquals(tc, 23.0, get_param_flt(par, "foo", 0.0), 0.01); CuAssertDblEquals(tc, 42.0, get_param_flt(par, "bar", 0.0), 0.01); free_params(&par); - test_cleanup(); + test_teardown(); } static void test_forbiddenid(CuTest *tc) { @@ -189,7 +189,7 @@ static void test_default_order(CuTest *tc) { CuAssertPtrNotNull(tc, ord); CuAssertIntEquals(tc, K_WORK, getkeyword(ord)); free_order(ord); - test_cleanup(); + test_teardown(); } static void test_config_cache(CuTest *tc) { @@ -202,7 +202,7 @@ static void test_config_cache(CuTest *tc) { CuAssertTrue(tc, !config_changed(&key)); free_config(); CuAssertTrue(tc, config_changed(&key)); - test_cleanup(); + test_teardown(); } static void test_rules(CuTest *tc) { @@ -247,7 +247,7 @@ static void test_config_inifile(CuTest *tc) { CuAssertStrEquals(tc, "Eressea", game_name()); CuAssertIntEquals(tc, 42, game_id()); iniparser_freedict(ini); - test_cleanup(); + test_teardown(); } static void test_findparam(CuTest *tc) { @@ -270,7 +270,7 @@ static void test_findparam(CuTest *tc) { CuAssertIntEquals(tc, P_FACTION, findparam_block("PARTEI", de, true)); CuAssertIntEquals(tc, NOPARAM, findparam_block("PARTEI", en, false)); CuAssertIntEquals(tc, P_FACTION, findparam_block("PARTEI", en, true)); - test_cleanup(); + test_teardown(); } static void test_game_mailcmd(CuTest *tc) { @@ -283,7 +283,7 @@ static void test_game_mailcmd(CuTest *tc) { CuAssertStrEquals(tc, "HODOR", game_mailcmd()); config_set("game.mailcmd", "ERESSEA"); CuAssertStrEquals(tc, "ERESSEA", game_mailcmd()); - test_cleanup(); + test_teardown(); } CuSuite *get_config_suite(void) diff --git a/src/kernel/connection.c b/src/kernel/connection.c index b630429fe..516cb6ead 100644 --- a/src/kernel/connection.c +++ b/src/kernel/connection.c @@ -16,7 +16,9 @@ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. **/ +#ifdef _MSC_VER #include +#endif #include #include "connection.h" @@ -25,19 +27,22 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "unit.h" #include -#include +#include #include #include #include -#include +#include #include +#include +#include #include /* libc includes */ #include #include #include +#include #include int nextborder = 0; @@ -131,7 +136,8 @@ static connection **get_borders_i(const region * r1, const region * r2) int key = reg_hashkey(r1); int k2 = reg_hashkey(r2); - key = MIN(k2, key) % BORDER_MAXHASH; + if (key > k2) key = k2; + key = key % BORDER_MAXHASH; bp = &borders[key]; while (*bp) { connection *b = *bp; @@ -512,10 +518,11 @@ static const char *b_nameroad(const connection * b, const region * r, } } else { - int percent = MAX(1, 100 * local / r->terrain->max_road); if (local) { - slprintf(buffer, sizeof(buffer), LOC(f->locale, mkname("border", - "a_road_percent")), percent); + const char *temp = LOC(f->locale, mkname("border", "a_road_percent")); + int percent = 100 * local / r->terrain->max_road; + if (percent < 1) percent = 1; + str_replace(buffer, sizeof(buffer), temp, "$percent", itoa10(percent)); } else { return LOC(f->locale, mkname("border", "a_road_connection")); diff --git a/src/kernel/curse.c b/src/kernel/curse.c index 499db9e93..0f215dbee 100644 --- a/src/kernel/curse.c +++ b/src/kernel/curse.c @@ -16,7 +16,9 @@ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. **/ +#ifdef _MSC_VER #include +#endif #include #include "curse.h" @@ -38,6 +40,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include #include #include #include @@ -323,7 +326,8 @@ const curse_type *ct_find(const char *c) return type; } else { - size_t k = MIN(c_len, strlen(type->cname)); + size_t k = strlen(type->cname); + if (k > c_len) k = c_len; if (!memcmp(c, type->cname, k)) { return type; } @@ -482,7 +486,7 @@ int get_cursedmen(const unit * u, const curse * c) cursedmen = c->data.i; } - return MIN(u->number, cursedmen); + return (u->number < cursedmen) ? u->number : cursedmen; } /* setzt die Anzahl der betroffenen Personen auf cursedmen */ @@ -571,19 +575,19 @@ curse *create_curse(unit * magician, attrib ** ap, const curse_type * ct, /* es gibt schon eins diese Typs */ if (c && ct->mergeflags != NO_MERGE) { if (ct->mergeflags & M_DURATION) { - c->duration = MAX(c->duration, duration); + if (c->duration < duration) c->duration = duration; } else if (ct->mergeflags & M_SUMDURATION) { c->duration += duration; } if (ct->mergeflags & M_MAXEFFECT) { - c->effect = MAX(c->effect, effect); + if (c->effect < effect) c->effect = effect; } else if (ct->mergeflags & M_SUMEFFECT) { c->effect += effect; } if (ct->mergeflags & M_VIGOUR) { - c->vigour = MAX(vigour, c->vigour); + if (c->vigour < vigour) c->vigour = vigour; } else if (ct->mergeflags & M_VIGOUR_ADD) { c->vigour = vigour + c->vigour; @@ -722,6 +726,7 @@ message *cinfo_simple(const void *obj, objtype_t typ, const struct curse * c, UNUSED_ARG(obj); msg = msg_message(mkname("curseinfo", c->type->cname), "id", c->no); + /* TODO: this is never NULL, because of the missing_message logic (used in many tests) */ if (msg == NULL) { log_error("There is no curseinfo for %s.\n", c->type->cname); } diff --git a/src/kernel/curse.test.c b/src/kernel/curse.test.c index 10c03a991..9c74544e1 100644 --- a/src/kernel/curse.test.c +++ b/src/kernel/curse.test.c @@ -31,6 +31,8 @@ static void test_curse(CuTest * tc) int cid; curse_type ct_dummy = { "dummy", CURSETYP_NORM, 0, M_SUMEFFECT, NULL }; + + test_setup(); c = create_curse(NULL, &attrs, &ct_dummy, 1.0, 1, 1, 1); cid = c->no; result = findcurse(cid); @@ -38,7 +40,7 @@ static void test_curse(CuTest * tc) a_remove(&attrs, attrs); result = findcurse(cid); CuAssertPtrEquals(tc, NULL, result); - test_cleanup(); + test_teardown(); } typedef struct { @@ -48,14 +50,15 @@ typedef struct { } curse_fixture; static void setup_curse(curse_fixture *fix, const char *name) { - test_cleanup(); + test_setup(); + test_inject_messagetypes(); fix->r = test_create_region(0, 0, NULL); fix->u = test_create_unit(test_create_faction(NULL), fix->r); fix->c = create_curse(fix->u, &fix->r->attribs, ct_find(name), 1.0, 1, 1.0, 0); } -static void cleanup_curse(curse_fixture *fix) { - test_cleanup(); +static void teardown_curse(curse_fixture *fix) { + test_teardown(); } static void test_magicstreet(CuTest *tc) { @@ -66,7 +69,7 @@ static void test_magicstreet(CuTest *tc) { msg = fix.c->type->curseinfo(fix.r, TYP_REGION, fix.c, 0); CuAssertStrEquals(tc, "curseinfo::magicstreet", test_get_messagetype(msg)); msg_release(msg); - cleanup_curse(&fix); + teardown_curse(&fix); } static void test_magicstreet_warning(CuTest *tc) { @@ -77,7 +80,7 @@ static void test_magicstreet_warning(CuTest *tc) { msg = fix.c->type->curseinfo(fix.r, TYP_REGION, fix.c, 0); CuAssertStrEquals(tc, "curseinfo::magicstreetwarn", test_get_messagetype(msg)); msg_release(msg); - cleanup_curse(&fix); + teardown_curse(&fix); } static void test_good_dreams(CuTest *tc) { @@ -88,7 +91,7 @@ static void test_good_dreams(CuTest *tc) { msg = fix.c->type->curseinfo(fix.r, TYP_REGION, fix.c, 0); CuAssertStrEquals(tc, "curseinfo::gooddream", test_get_messagetype(msg)); msg_release(msg); - cleanup_curse(&fix); + teardown_curse(&fix); } static void test_bad_dreams(CuTest *tc) { @@ -99,7 +102,7 @@ static void test_bad_dreams(CuTest *tc) { msg = fix.c->type->curseinfo(fix.r, TYP_REGION, fix.c, 0); CuAssertStrEquals(tc, "curseinfo::baddream", test_get_messagetype(msg)); msg_release(msg); - cleanup_curse(&fix); + teardown_curse(&fix); } static void test_memstream(CuTest *tc) { @@ -156,7 +159,7 @@ static void test_write_flag(CuTest *tc) { mstream_done(&data.strm); gamedata_done(&data); - cleanup_curse(&fix); + teardown_curse(&fix); } static void test_curse_ids(CuTest *tc) { @@ -172,7 +175,7 @@ static void test_curse_ids(CuTest *tc) { CuAssertTrue(tc, c1->no != c2->no); a_remove(&a1, a1); a_remove(&a2, a2); - test_cleanup(); + test_teardown(); } static void test_curse_flags(CuTest *tc) { @@ -181,7 +184,7 @@ static void test_curse_flags(CuTest *tc) { unit *u; test_setup(); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); c1 = create_curse(u, &u->attribs, &ct_dummy, 1, 1, 1, 0); CuAssertPtrEquals(tc, u, c1->magician); CuAssertIntEquals(tc, 1, (int)c1->effect); @@ -193,7 +196,7 @@ static void test_curse_flags(CuTest *tc) { CuAssertIntEquals(tc, 2, (int)c1->effect); CuAssertIntEquals(tc, 1, (int)c1->vigour); CuAssertIntEquals(tc, 1, c1->duration); - test_cleanup(); + test_teardown(); } CuSuite *get_curse_suite(void) diff --git a/src/kernel/database.c b/src/kernel/database.c new file mode 100644 index 000000000..eaf695613 --- /dev/null +++ b/src/kernel/database.c @@ -0,0 +1,38 @@ +#include +#include "database.h" + +#include + +#include +#include +#include + +#include + +#include "db/driver.h" + +order_data *dblib_load_order(int id) +{ + if (id > 0) { + return db_driver_order_load(id); + } + return NULL; +} + +int dblib_save_order(order_data *od) +{ + if (od->_str) { + return db_driver_order_save(od); + } + return 0; +} + +void dblib_open(void) +{ + db_driver_open(); +} + +void dblib_close(void) +{ + db_driver_close(); +} diff --git a/src/kernel/database.h b/src/kernel/database.h new file mode 100644 index 000000000..0dd5a70fb --- /dev/null +++ b/src/kernel/database.h @@ -0,0 +1,21 @@ +#ifndef H_DATABASE +#define H_DATABASE + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + struct order_data; + + void dblib_open(void); + void dblib_close(void); + + struct order_data *dblib_load_order(int id); + int dblib_save_order(struct order_data *od); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/database.test.c b/src/kernel/database.test.c new file mode 100644 index 000000000..2e1104185 --- /dev/null +++ b/src/kernel/database.test.c @@ -0,0 +1,40 @@ +#include +#include + +#include "database.h" +#include "orderdb.h" + +#include +#include + +#include + +static void test_save_load_order(CuTest *tc) { + order_data *od; + int id; + const char * s = "GIB enno 1 Hodor"; + + test_setup(); + + odata_create(&od, strlen(s) + 1, s); + CuAssertTrue(tc, od->_refcount >= 1); + id = odata_save(od); + odata_release(od); + CuAssertTrue(tc, id != 0); + + od = odata_load(id); + CuAssertPtrNotNull(tc, od); + CuAssertTrue(tc, od->_refcount >= 1); + CuAssertStrEquals(tc, s, od->_str); + odata_release(od); + + test_teardown(); +} + +CuSuite *get_db_suite(void) +{ + CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_save_load_order); + + return suite; +} diff --git a/src/kernel/db/berkeley.c b/src/kernel/db/berkeley.c new file mode 100644 index 000000000..210c36f01 --- /dev/null +++ b/src/kernel/db/berkeley.c @@ -0,0 +1,76 @@ +#include +#include + +#include +#include "driver.h" + +#include +#include + +#include +#include + +static DB *g_dbp; + +void db_driver_open(void) +{ + int ret; + u_int32_t flags = DB_CREATE; + const char * dbname; + + dbname = config_get("game.dbname"); + ret = db_create(&g_dbp, NULL, 0); + assert(ret==0); + + ret = g_dbp->open(g_dbp, NULL, dbname, NULL, DB_RECNO, flags, 0); + assert(ret==0); +} + +void db_driver_close(void) +{ + int ret; + ret = g_dbp->close(g_dbp, 0); + assert(ret==0); +} + +int db_driver_order_save(struct order_data *od) +{ + int ret; + DBT key, data; + db_recno_t recno; + + assert(od && od->_str); + memset(&key, 0, sizeof(DBT)); + memset(&data, 0, sizeof(DBT)); + key.data = &recno; + key.size = key.ulen = sizeof(recno); + key.flags = DB_DBT_USERMEM; + data.data = (void *)od->_str; + data.size = data.ulen = strlen(od->_str) + 1; + data.flags = DB_DBT_USERMEM; + ret = g_dbp->put(g_dbp, NULL, &key, &data, DB_APPEND); + assert(ret == 0); + return (int)recno; +} + +struct order_data *db_driver_order_load(int id) +{ + int ret; + order_data *od = NULL; + DBT key, data; + db_recno_t recno; + + assert(id>0); + memset(&key, 0, sizeof(DBT)); + memset(&data, 0, sizeof(DBT)); + recno = (db_recno_t)id; + key.data = &recno; + key.size = key.ulen = sizeof(recno); + key.flags = DB_DBT_USERMEM; + ret = g_dbp->get(g_dbp, NULL, &key, &data, 0); + if (ret == 0) { + odata_create(&od, data.size, data.data); + } + return od; +} + diff --git a/src/kernel/db/critbit.c b/src/kernel/db/critbit.c new file mode 100644 index 000000000..9afb0926d --- /dev/null +++ b/src/kernel/db/critbit.c @@ -0,0 +1,67 @@ +#include +#include "driver.h" + +#include +#include + +#include + +#include +#include +#include + +static critbit_tree cb_orders = { 0 }; +static int auto_id = -1; + +struct cb_entry { + int id; + order_data *data; +}; + +order_data *db_driver_order_load(int id) +{ + void * match; + + assert(id>0); + if (cb_find_prefix(&cb_orders, &id, sizeof(id), &match, 1, 0) > 0) { + struct cb_entry *ent = (struct cb_entry *)match; + order_data * od = ent->data; + ++od->_refcount; + return od; + } + return NULL; +} + +int db_driver_order_save(order_data *od) +{ + struct cb_entry ent; + + assert(od && od->_str); + ++od->_refcount; + ent.id = ++auto_id; + ent.data = od; + cb_insert(&cb_orders, &ent, sizeof(ent)); + return ent.id; +} + +static int free_data_cb(const void *match, const void *key, size_t keylen, + void *udata) +{ + struct cb_entry * ent = (struct cb_entry *)match; + order_data *od = ent->data; + odata_release(od); + return 0; +} + +void db_driver_open(void) +{ + assert(auto_id == -1); + auto_id = 0; +} + +void db_driver_close(void) +{ + cb_foreach(&cb_orders, NULL, 0, free_data_cb, NULL); + cb_clear(&cb_orders); + auto_id = -1; +} diff --git a/src/kernel/db/driver.h b/src/kernel/db/driver.h new file mode 100644 index 000000000..df839b93d --- /dev/null +++ b/src/kernel/db/driver.h @@ -0,0 +1,8 @@ +#pragma once + +struct order_data; + +void db_driver_open(void); +void db_driver_close(void); +int db_driver_order_save(struct order_data *od); +struct order_data *db_driver_order_load(int id); diff --git a/src/kernel/db/sqlite.c b/src/kernel/db/sqlite.c new file mode 100644 index 000000000..965363223 --- /dev/null +++ b/src/kernel/db/sqlite.c @@ -0,0 +1,123 @@ +#include + +#include +#include +#include + +#include + +#include "driver.h" + +#include + +#include +#include +#include +#include + +static sqlite3 *g_db; +static sqlite3_stmt * g_stmt_insert; +static sqlite3_stmt * g_stmt_select; + +static int g_order_batchsize; +static int g_order_tx_size; + +order_data *db_driver_order_load(int id) +{ + order_data * od = NULL; + int err; + + if (g_order_tx_size > 0) { + g_order_tx_size = 0; + err = sqlite3_exec(g_db, "COMMIT", NULL, NULL, NULL); + assert(err == SQLITE_OK); + } + err = sqlite3_reset(g_stmt_select); + assert(err == SQLITE_OK); + err = sqlite3_bind_int(g_stmt_select, 1, id); + assert(err == SQLITE_OK); + do { + err = sqlite3_step(g_stmt_select); + if (err == SQLITE_ROW) { + const unsigned char *text; + int bytes; + bytes = sqlite3_column_bytes(g_stmt_select, 0); + assert(bytes > 0); + text = sqlite3_column_text(g_stmt_select, 0); + odata_create(&od, 1+(size_t)bytes, (const char *)text); + return od; + } + } while (err == SQLITE_ROW); + assert(err == SQLITE_DONE); + return NULL; +} + +int db_driver_order_save(order_data *od) +{ + int err; + sqlite3_int64 id; + + assert(od && od->_str); + + if (g_order_batchsize > 0) { + if (g_order_tx_size == 0) { + err = sqlite3_exec(g_db, "BEGIN TRANSACTION", NULL, NULL, NULL); + assert(err == SQLITE_OK); + } + } + + err = sqlite3_reset(g_stmt_insert); + assert(err == SQLITE_OK); + err = sqlite3_bind_text(g_stmt_insert, 1, od->_str, -1, SQLITE_STATIC); + assert(err == SQLITE_OK); + err = sqlite3_step(g_stmt_insert); + assert(err == SQLITE_DONE); + id = sqlite3_last_insert_rowid(g_db); + assert(id <= INT_MAX); + + if (g_order_batchsize > 0) { + if (++g_order_tx_size >= g_order_batchsize) { + err = sqlite3_exec(g_db, "COMMIT", NULL, NULL, NULL); + assert(err == SQLITE_OK); + g_order_tx_size = 0; + } + } + + return (int)id; +} + +void db_driver_open(void) +{ + int err; + const char *dbname; + + g_order_batchsize = config_get_int("game.dbbatch", 100); + dbname = config_get("game.dbname"); + if (!dbname) { + dbname = ""; + } + err = sqlite3_open(dbname, &g_db); + assert(err == SQLITE_OK); + err = sqlite3_exec(g_db, "PRAGMA journal_mode=OFF", NULL, NULL, NULL); + assert(err == SQLITE_OK); + err = sqlite3_exec(g_db, "PRAGMA synchronous=OFF", NULL, NULL, NULL); + assert(err == SQLITE_OK); + err = sqlite3_exec(g_db, "CREATE TABLE IF NOT EXISTS orders (id INTEGER PRIMARY KEY, data TEXT NOT NULL)", NULL, NULL, NULL); + assert(err == SQLITE_OK); + err = sqlite3_prepare_v2(g_db, "INSERT INTO orders (data) VALUES (?)", -1, &g_stmt_insert, NULL); + assert(err == SQLITE_OK); + err = sqlite3_prepare_v2(g_db, "SELECT data FROM orders WHERE id = ?", -1, &g_stmt_select, NULL); + assert(err == SQLITE_OK); +} + +void db_driver_close(void) +{ + int err; + + err = sqlite3_finalize(g_stmt_select); + assert(err == SQLITE_OK); + err = sqlite3_finalize(g_stmt_insert); + assert(err == SQLITE_OK); + err = sqlite3_close(g_db); + assert(err == SQLITE_OK); +} diff --git a/src/kernel/equipment.c b/src/kernel/equipment.c index f24d4acfd..99c0bba7b 100644 --- a/src/kernel/equipment.c +++ b/src/kernel/equipment.c @@ -33,6 +33,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include /* libc includes */ #include @@ -43,7 +44,7 @@ void equipment_setskill(equipment * eq, skill_t sk, const char *value) { if (eq != NULL) { if (value != NULL) { - eq->skills[sk] = strdup(value); + eq->skills[sk] = str_strdup(value); } else if (eq->skills[sk]) { free(eq->skills[sk]); @@ -78,7 +79,7 @@ equipment_setitem(equipment * eq, const item_type * itype, const char *value) if (idata == NULL) { idata = (itemdata *)malloc(sizeof(itemdata)); idata->itype = itype; - idata->value = strdup(value); + idata->value = str_strdup(value); idata->next = eq->items; eq->items = idata; } @@ -292,7 +293,12 @@ static void free_equipment(equipment *eq) { free(eq->items); eq->items = next; } - /* TODO: subsets, skills */ + if (eq->subsets) { + for (i = 0; eq->subsets[i].sets; ++i) { + free(eq->subsets[i].sets); + } + free(eq->subsets); + } for (i = 0; i != MAXSKILLS; ++i) { free(eq->skills[i]); } diff --git a/src/kernel/equipment.test.c b/src/kernel/equipment.test.c index 0e0ebf196..5c0757601 100644 --- a/src/kernel/equipment.test.c +++ b/src/kernel/equipment.test.c @@ -34,7 +34,7 @@ static void test_equipment(CuTest * tc) equipment_setskill(eq, SK_MAGIC, "5"); equipment_addspell(eq, sp->sname, 1); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); equip_unit_mask(u, eq, EQUIP_ALL); CuAssertIntEquals(tc, 1, i_get(u->items, it_horses)); CuAssertIntEquals(tc, 5, get_level(u, SK_MAGIC)); @@ -43,7 +43,7 @@ static void test_equipment(CuTest * tc) CuAssertPtrNotNull(tc, mage); CuAssertPtrNotNull(tc, mage->spellbook); CuAssertTrue(tc, u_hasspell(u, sp)); - test_cleanup(); + test_teardown(); } static void test_get_equipment(CuTest * tc) @@ -66,7 +66,7 @@ static void test_get_equipment(CuTest * tc) eq = get_equipment("catapultammo123"); CuAssertPtrNotNull(tc, eq); CuAssertStrEquals(tc, "catapultammo123", equipment_name(eq)); - test_cleanup(); + test_teardown(); } CuSuite *get_equipment_suite(void) diff --git a/src/kernel/faction.c b/src/kernel/faction.c index 98e49bd84..90649600f 100755 --- a/src/kernel/faction.c +++ b/src/kernel/faction.c @@ -35,11 +35,11 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include +#include /* util includes */ #include #include -#include #include #include #include @@ -48,8 +48,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include #include #include +#include #include #include @@ -195,7 +197,7 @@ const char *factionname(const faction * f) char *ibuf = idbuf[(++nextbuf) % 8]; if (f && f->name) { - slprintf(ibuf, sizeof(name), "%s (%s)", f->name, itoa36(f->no)); + slprintf(ibuf, sizeof(idbuf[0]), "%s (%s)", f->name, itoa36(f->no)); } else { strcpy(ibuf, "Unbekannte Partei (?)"); @@ -229,8 +231,11 @@ faction *addfaction(const char *email, const char *password, faction *f = calloc(sizeof(faction), 1); char buf[128]; - if (set_email(&f->email, email) != 0) { - log_warning("Invalid email address for faction %s: %s\n", itoa36(f->no), email); + if (check_email(email) == 0) { + faction_setemail(f, email); + } else { + log_warning("Invalid email address for faction %s: %s\n", itoa36(f->no), email?email:""); + faction_setemail(f, NULL); } f->alliance_joindate = turn; @@ -248,8 +253,9 @@ faction *addfaction(const char *email, const char *password, ADDMSG(&f->msgs, msg_message("changepasswd", "value", password)); f->options = - want(O_REPORT) | want(O_ZUGVORLAGE) | want(O_COMPUTER) | want(O_COMPRESS) | - want(O_ADRESSEN) | want(O_STATISTICS); + WANT_OPTION(O_REPORT) | WANT_OPTION(O_ZUGVORLAGE) | + WANT_OPTION(O_COMPUTER) | WANT_OPTION(O_COMPRESS) | + WANT_OPTION(O_ADRESSEN) | WANT_OPTION(O_STATISTICS); f->no = unused_faction_id(); if (rule_region_owners()) { @@ -260,7 +266,7 @@ faction *addfaction(const char *email, const char *password, fhash(f); slprintf(buf, sizeof(buf), "%s %s", LOC(loc, "factiondefault"), itoa36(f->no)); - f->name = strdup(buf); + f->name = str_strdup(buf); if (!f->race) { log_warning("creating a faction that has no race", itoa36(f->no)); @@ -311,7 +317,7 @@ bool checkpasswd(const faction * f, const char *passwd) if (!passwd) return false; if (f->_password && password_verify(f->_password, passwd) == VERIFY_FAIL) { - log_warning("password check failed: %s", factionname(f)); + log_info("password check failed: %s", factionname(f)); return false; } return true; @@ -358,6 +364,69 @@ void free_flist(faction **fp) { static faction *dead_factions; +static void give_special_items(unit *u, item **items) { + item **iter = items; + while (*iter) { + item *itm = *iter; + if (itm->number > 0 && itm->type->flags & ITF_NOTLOST) { + i_change(&u->items, itm->type, itm->number); + *iter = itm->next; + if (iter == items) { + *items = *iter; + } + i_free(itm); + } + else { + iter = &itm->next; + } + } +} + +faction *get_or_create_monsters(void) +{ + faction *f = findfaction(MONSTER_ID); + if (!f) { + const race *rc = rc_get_or_create("dragon"); + const char *email = config_get("monster.email"); + f = addfaction(email, NULL, rc, default_locale, 0); + renumber_faction(f, MONSTER_ID); + faction_setname(f, "Monster"); + fset(f, FFL_NPC | FFL_NOIDLEOUT); + } + return f; +} + +faction *get_monsters(void) { + return get_or_create_monsters(); +} + +void save_special_items(unit *usrc) +{ + unit *u; + region *r = usrc->region; + faction *fm = get_monsters(); + static const race *rc_ghost; + static int cache; + + if (rc_changed(&cache)) { + rc_ghost = get_race(RC_TEMPLATE); + } + for (u = r->units; u; u = u->next) { + if (u->faction == fm) { + give_special_items(u, &usrc->items); + return; + } + } + u = create_unit(r, fm, 1, rc_ghost, 0, NULL, NULL); + unit_setname(u, unit_getname(usrc)); + if (usrc->number > 1) { + /* some units have plural names, it would be neat if they aren't single: */ + scale_number(u, 2); + } + set_racename(&u->attribs, "ghost"); + give_special_items(u, &usrc->items); +} + void destroyfaction(faction ** fp) { faction * f = *fp; @@ -382,22 +451,19 @@ void destroyfaction(faction ** fp) } while (u) { - /* give away your stuff, make zombies if you cannot (quest items) */ - int result = gift_items(u, GIFT_FRIENDS | GIFT_PEASANTS); - if (result != 0) { - unit *zombie = u; - u = u->nextF; - make_zombie(zombie); - } - else { + /* give away your stuff, to ghosts if you cannot (quest items) */ + if (u->items) { region *r = u->region; - + int result = gift_items(u, GIFT_FRIENDS | GIFT_PEASANTS); + if (result != 0) { + save_special_items(u); + } if (r->land && !!playerrace(u_race(u))) { const race *rc = u_race(u); int m = rmoney(r); /* Personen gehen nur an die Bauern, wenn sie auch von dort - * stammen */ + * stammen */ if ((rc->ec_flags & ECF_REC_ETHEREAL) == 0) { int p = rpeasants(u->region); int h = rhorses(u->region); @@ -415,9 +481,9 @@ void destroyfaction(faction ** fp) m += get_money(u); rsetmoney(r, m); } - set_number(u, 0); - u = u->nextF; } + set_number(u, 0); + u = u->nextF; } handle_event(f->attribs, "destroy", f); @@ -531,7 +597,7 @@ void faction_setname(faction * self, const char *name) { free(self->name); if (name) - self->name = strdup(name); + self->name = str_strdup(name); } const char *faction_getemail(const faction * self) @@ -543,7 +609,9 @@ void faction_setemail(faction * self, const char *email) { free(self->email); if (email) - self->email = strdup(email); + self->email = str_strdup(email); + else + self->email = NULL; } const char *faction_getbanner(const faction * self) @@ -555,14 +623,14 @@ void faction_setbanner(faction * self, const char *banner) { free(self->banner); if (banner) - self->banner = strdup(banner); + self->banner = str_strdup(banner); } void faction_setpassword(faction * f, const char *pwhash) { assert(pwhash); free(f->_password); - f->_password = strdup(pwhash); + f->_password = str_strdup(pwhash); } bool valid_race(const struct faction *f, const struct race *rc) @@ -786,7 +854,7 @@ int writepasswd(void) FILE *F; char zText[128]; - join_path(basepath(), "passwd", zText, sizeof(zText)); + path_join(basepath(), "passwd", zText, sizeof(zText)); F = fopen(zText, "w"); if (!F) { perror(zText); @@ -797,7 +865,7 @@ int writepasswd(void) for (f = factions; f; f = f->next) { fprintf(F, "%s:%s:%s:%d\n", - itoa36(f->no), f->email, f->_password, f->subscription); + itoa36(f->no), faction_getemail(f), f->_password, f->subscription); } fclose(F); return 0; diff --git a/src/kernel/faction.h b/src/kernel/faction.h index a04acabfa..25913e73d 100644 --- a/src/kernel/faction.h +++ b/src/kernel/faction.h @@ -84,9 +84,6 @@ extern "C" { score_t score; struct alliance *alliance; int alliance_joindate; /* the turn on which the faction joined its current alliance (or left the last one) */ -#ifdef VICTORY_DELAY - unsigned char victory_delay; -#endif struct unit *units; struct attrib *attribs; struct message_list *msgs; @@ -102,7 +99,7 @@ extern "C" { extern struct faction *factions; -#define want(option) (1<no==MONSTER_ID) #ifdef __cplusplus } diff --git a/src/kernel/faction.test.c b/src/kernel/faction.test.c index 7901cd96f..904609be5 100644 --- a/src/kernel/faction.test.c +++ b/src/kernel/faction.test.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -12,6 +13,8 @@ #include #include +#include + #include "monsters.h" #include #include @@ -25,11 +28,11 @@ static void test_destroyfaction_allies(CuTest *tc) { region *r; ally *al; - test_cleanup(); - r = test_create_region(0, 0, 0); - f1 = test_create_faction(0); + test_setup(); + r = test_create_region(0, 0, NULL); + f1 = test_create_faction(NULL); test_create_unit(f1, r); - f2 = test_create_faction(0); + f2 = test_create_faction(NULL); al = ally_add(&f1->allies, f2); al->status = HELP_FIGHT; CuAssertIntEquals(tc, HELP_FIGHT, alliedgroup(0, f1, f2, f1->allies, HELP_ALL)); @@ -37,15 +40,15 @@ static void test_destroyfaction_allies(CuTest *tc) { destroyfaction(&f1->next); CuAssertIntEquals(tc, false, faction_alive(f2)); CuAssertIntEquals(tc, 0, alliedgroup(0, f1, f2, f1->allies, HELP_ALL)); - test_cleanup(); + test_teardown(); } static void test_remove_empty_factions_alliance(CuTest *tc) { faction *f; struct alliance *al; - test_cleanup(); - f = test_create_faction(0); + test_setup(); + f = test_create_faction(NULL); al = makealliance(0, "Hodor"); setalliance(f, al); CuAssertPtrEquals(tc, f, alliance_get_leader(al)); @@ -53,17 +56,17 @@ static void test_remove_empty_factions_alliance(CuTest *tc) { remove_empty_factions(); CuAssertPtrEquals(tc, 0, al->_leader); CuAssertIntEquals(tc, 0, selist_length(al->members)); - test_cleanup(); + test_teardown(); } static void test_remove_empty_factions(CuTest *tc) { faction *f, *fm; int fno; - test_cleanup(); + test_setup(); fm = get_or_create_monsters(); assert(fm); - f = test_create_faction(0); + f = test_create_faction(NULL); fno = f->no; remove_empty_factions(); CuAssertIntEquals(tc, false, f->_alive); @@ -71,7 +74,7 @@ static void test_remove_empty_factions(CuTest *tc) { CuAssertPtrEquals(tc, NULL, fm->next); CuAssertPtrEquals(tc, 0, findfaction(fno)); CuAssertPtrEquals(tc, fm, get_monsters()); - test_cleanup(); + test_teardown(); } static void test_remove_dead_factions(CuTest *tc) { @@ -79,10 +82,10 @@ static void test_remove_dead_factions(CuTest *tc) { region *r; int fno; - test_cleanup(); - r = test_create_region(0, 0, 0); + test_setup(); + r = test_create_region(0, 0, NULL); fm = get_or_create_monsters(); - f = test_create_faction(0); + f = test_create_faction(NULL); assert(fm && r && f); test_create_unit(f, r); test_create_unit(fm, r); @@ -95,7 +98,7 @@ static void test_remove_dead_factions(CuTest *tc) { remove_empty_factions(); CuAssertPtrEquals(tc, 0, findfaction(fno)); CuAssertPtrEquals(tc, fm, get_monsters()); - test_cleanup(); + test_teardown(); } static void test_addfaction(CuTest *tc) { @@ -103,7 +106,7 @@ static void test_addfaction(CuTest *tc) { const struct race *rc; const struct locale *lang; - test_cleanup(); + test_setup(); rc = rc_get_or_create("human"); lang = test_create_locale(); f = addfaction("test@eressea.de", "hurrdurr", rc, lang, 1234); @@ -125,13 +128,13 @@ static void test_addfaction(CuTest *tc) { CuAssertIntEquals(tc, M_GRAY, f->magiegebiet); CuAssertIntEquals(tc, turn, f->lastorders); CuAssertPtrEquals(tc, f, findfaction(f->no)); - test_cleanup(); + test_teardown(); } static void test_check_passwd(CuTest *tc) { faction *f; - f = test_create_faction(0); + f = test_create_faction(NULL); faction_setpassword(f, password_encode("password", PASSWORD_DEFAULT)); CuAssertTrue(tc, checkpasswd(f, "password")); CuAssertTrue(tc, !checkpasswd(f, "assword")); @@ -141,12 +144,12 @@ static void test_check_passwd(CuTest *tc) { static void test_get_monsters(CuTest *tc) { faction *f; - free_gamedata(); + test_setup(); CuAssertPtrNotNull(tc, (f = get_monsters())); CuAssertPtrEquals(tc, f, get_monsters()); CuAssertIntEquals(tc, 666, f->no); CuAssertStrEquals(tc, "Monster", f->name); - test_cleanup(); + test_teardown(); } static void test_set_origin(CuTest *tc) { @@ -156,7 +159,7 @@ static void test_set_origin(CuTest *tc) { test_setup(); pl = create_new_plane(0, "", 0, 19, 0, 19, 0); - f = test_create_faction(0); + f = test_create_faction(NULL); CuAssertPtrEquals(tc, 0, f->ursprung); faction_setorigin(f, 0, 1, 1); CuAssertIntEquals(tc, 0, f->ursprung->id); @@ -171,7 +174,7 @@ static void test_set_origin(CuTest *tc) { adjust_coordinates(f, &x, &y, 0); CuAssertIntEquals(tc, -10, x); CuAssertIntEquals(tc, -10, y); - test_cleanup(); + test_teardown(); } static void test_set_origin_bug(CuTest *tc) { @@ -181,14 +184,14 @@ static void test_set_origin_bug(CuTest *tc) { test_setup(); pl = create_new_plane(0, "", 0, 19, 0, 19, 0); - f = test_create_faction(0); + f = test_create_faction(NULL); faction_setorigin(f, 0, -10, 3); faction_setorigin(f, 0, -13, -4); adjust_coordinates(f, &x, &y, pl); CuAssertIntEquals(tc, 0, f->ursprung->id); CuAssertIntEquals(tc, -9, x); CuAssertIntEquals(tc, 2, y); - test_cleanup(); + test_teardown(); } static void test_max_migrants(CuTest *tc) { @@ -199,13 +202,13 @@ static void test_max_migrants(CuTest *tc) { test_setup(); rc = test_create_race("human"); f = test_create_faction(rc); - u = test_create_unit(f, test_create_region(0, 0, 0)); + u = test_create_unit(f, test_create_region(0, 0, NULL)); CuAssertIntEquals(tc, 0, count_maxmigrants(f)); rc->flags |= RCF_MIGRANTS; CuAssertIntEquals(tc, 0, count_maxmigrants(f)); scale_number(u, 250); CuAssertIntEquals(tc, 13, count_maxmigrants(f)); - test_cleanup(); + test_teardown(); } static void test_valid_race(CuTest *tc) { @@ -221,22 +224,77 @@ static void test_valid_race(CuTest *tc) { rc_set_param(rc1, "other_race", "elf"); CuAssertTrue(tc, valid_race(f, rc1)); CuAssertTrue(tc, valid_race(f, rc2)); - test_cleanup(); + test_teardown(); } static void test_set_email(CuTest *tc) { - char * email = NULL; + faction *f; + char email[10]; test_setup(); - CuAssertIntEquals(tc, 0, set_email(&email, "enno@eressea.de")); - CuAssertStrEquals(tc, "enno@eressea.de", email); - CuAssertIntEquals(tc, 0, set_email(&email, "bugs@eressea.de")); - CuAssertStrEquals(tc, "bugs@eressea.de", email); - CuAssertIntEquals(tc, -1, set_email(&email, "bad@@eressea.de")); - CuAssertIntEquals(tc, -1, set_email(&email, "eressea.de")); - CuAssertIntEquals(tc, -1, set_email(&email, "eressea@")); - CuAssertStrEquals(tc, "bugs@eressea.de", email); - free(email); - test_cleanup(); + CuAssertIntEquals(tc, 0, check_email("enno@eressea.de")); + CuAssertIntEquals(tc, 0, check_email("bugs@eressea.de")); + CuAssertIntEquals(tc, -1, check_email("bad@@eressea.de")); + CuAssertIntEquals(tc, -1, check_email("eressea.de")); + CuAssertIntEquals(tc, -1, check_email("eressea@")); + CuAssertIntEquals(tc, -1, check_email("")); + CuAssertIntEquals(tc, -1, check_email(NULL)); + f = test_create_faction(NULL); + + sprintf(email, "enno"); + faction_setemail(f, email); + email[0] = 0; + CuAssertStrEquals(tc, "enno", f->email); + CuAssertStrEquals(tc, "enno", faction_getemail(f)); + faction_setemail(f, "bugs@eressea.de"); + CuAssertStrEquals(tc, "bugs@eressea.de", f->email); + faction_setemail(f, NULL); + CuAssertPtrEquals(tc, 0, f->email); + CuAssertStrEquals(tc, "", faction_getemail(f)); + test_teardown(); +} + +static void test_save_special_items(CuTest *tc) { + unit *u, *ug; + race * rc; + struct item_type *itype, *it_silver, *it_horse; + + test_setup(); + it_horse = test_create_horse(); + it_silver = test_create_silver(); + itype = test_create_itemtype("banana"); + itype->flags |= ITF_NOTLOST; + rc = test_create_race("template"); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); + i_change(&u->items, itype, 1); + + /* when there is no monster in the region, a ghost of the dead unit is created: */ + save_special_items(u); + CuAssertPtrNotNull(tc, u->next); + ug = u->next; + CuAssertPtrEquals(tc, NULL, ug->next); + CuAssertPtrEquals(tc, rc, (void *)ug->_race); + CuAssertIntEquals(tc, 1, u->number); + CuAssertIntEquals(tc, 0, i_get(u->items, itype)); + CuAssertIntEquals(tc, 1, i_get(ug->items, itype)); + CuAssertStrEquals(tc, "ghost", get_racename(ug->attribs)); + CuAssertStrEquals(tc, u->_name, ug->_name); + + i_change(&u->items, itype, 1); + /* when there is a monster, it takes all special items: */ + save_special_items(u); + CuAssertPtrEquals(tc, NULL, ug->next); + CuAssertIntEquals(tc, 2, i_get(ug->items, itype)); + CuAssertPtrEquals(tc, NULL, u->items); + + i_change(&u->items, itype, 1); + i_change(&u->items, it_horse, 5); + i_change(&u->items, it_silver, 10); + /* horses and money need to go to the region and are not taken: */ + save_special_items(u); + CuAssertIntEquals(tc, 3, i_get(ug->items, itype)); + CuAssertIntEquals(tc, 5, i_get(u->items, it_horse)); + CuAssertIntEquals(tc, 10, i_get(u->items, it_silver)); + test_teardown(); } CuSuite *get_faction_suite(void) @@ -254,5 +312,6 @@ CuSuite *get_faction_suite(void) SUITE_ADD_TEST(suite, test_check_passwd); SUITE_ADD_TEST(suite, test_valid_race); SUITE_ADD_TEST(suite, test_set_email); + SUITE_ADD_TEST(suite, test_save_special_items); return suite; } diff --git a/src/kernel/group.c b/src/kernel/group.c index 2c6b28bec..54cd965da 100755 --- a/src/kernel/group.c +++ b/src/kernel/group.c @@ -34,6 +34,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include #include #include @@ -59,7 +60,7 @@ group *new_group(faction * f, const char *name, int gid) *gp = g; maxgid = MAX(gid, maxgid); - g->name = strdup(name); + g->name = str_strdup(name); g->gid = gid; g->nexthash = ghash[index]; diff --git a/src/kernel/group.test.c b/src/kernel/group.test.c index e95458114..d3bf4e2d9 100644 --- a/src/kernel/group.test.c +++ b/src/kernel/group.test.c @@ -31,14 +31,14 @@ static void test_group_readwrite_dead_faction(CuTest *tc) { ally *al; int fno; - test_cleanup(); - f = test_create_faction(0); + test_setup(); + f = test_create_faction(NULL); fno = f->no; CuAssertPtrEquals(tc, f, factions); CuAssertPtrEquals(tc, 0, f->next); - f2 = test_create_faction(0); + f2 = test_create_faction(NULL); CuAssertPtrEquals(tc, f2, factions->next); - u = test_create_unit(f2, test_create_region(0, 0, 0)); + u = test_create_unit(f2, test_create_region(0, 0, NULL)); CuAssertPtrNotNull(tc, u); g = join_group(u, "group"); CuAssertPtrNotNull(tc, g); @@ -66,7 +66,7 @@ static void test_group_readwrite_dead_faction(CuTest *tc) { g = get_group(u); CuAssertPtrNotNull(tc, g); CuAssertPtrEquals(tc, 0, g->allies); - test_cleanup(); + test_teardown(); } static void test_group_readwrite(CuTest * tc) @@ -78,10 +78,10 @@ static void test_group_readwrite(CuTest * tc) gamedata data; storage store; - test_cleanup(); + test_setup(); mstream_init(&data.strm); gamedata_init(&data, &store, RELEASE_VERSION); - f = test_create_faction(0); + f = test_create_faction(NULL); new_group(f, "NW", 42); g = new_group(f, "Egoisten", 43); key_set(&g->attribs, 44, 44); @@ -113,7 +113,7 @@ static void test_group_readwrite(CuTest * tc) CuAssertPtrEquals(tc, 0, g->allies->next); CuAssertPtrEquals(tc, f, g->allies->faction); CuAssertIntEquals(tc, HELP_GIVE, g->allies->status); - test_cleanup(); + test_teardown(); } static void test_group(CuTest * tc) @@ -123,9 +123,9 @@ static void test_group(CuTest * tc) faction *f; group *g; - test_cleanup(); - r = test_create_region(0, 0, 0); - f = test_create_faction(0); + test_setup(); + r = test_create_region(0, 0, NULL); + f = test_create_faction(NULL); assert(r && f); u = test_create_unit(f, r); assert(u); @@ -139,7 +139,7 @@ static void test_group(CuTest * tc) set_group(u, g); CuAssertIntEquals(tc, 1, g->members); CuAssertPtrEquals(tc, g, get_group(u)); - test_cleanup(); + test_teardown(); } CuSuite *get_group_suite(void) diff --git a/src/kernel/item.c b/src/kernel/item.c index 89c532297..74951895a 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -41,8 +41,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include #include #include +#include #include #include @@ -58,7 +60,6 @@ static critbit_tree inames[MAXLOCALES]; static critbit_tree rnames[MAXLOCALES]; static critbit_tree cb_resources; luxury_type *luxurytypes; -potion_type *potiontypes; #define RTYPENAMELEN 24 typedef struct rt_entry { @@ -105,10 +106,10 @@ static int res_changepeasants(unit * u, const resource_type * rtype, int delta) } static int golem_factor(const unit *u, const resource_type *rtype) { - if (rtype == get_resourcetype(R_STONE) && (u_race(u)->flags & RCF_STONEGOLEM)) { + if (rtype == get_resourcetype(R_STONE) && (u_race(u)->ec_flags & ECF_STONEGOLEM)) { return GOLEM_STONE; } - if (rtype == get_resourcetype(R_IRON) && (u_race(u)->flags & RCF_IRONGOLEM)) { + if (rtype == get_resourcetype(R_IRON) && (u_race(u)->ec_flags & ECF_IRONGOLEM)) { return GOLEM_IRON; } return 0; @@ -196,7 +197,7 @@ resource_type *rt_get_or_create(const char *name) { perror("resource_type allocation failed"); } else { - rtype->_name = strdup(name); + rtype->_name = str_strdup(name); rt_register(rtype); } } @@ -271,23 +272,21 @@ luxury_type *new_luxurytype(item_type * itype, int price) weapon_type *new_weapontype(item_type * itype, int wflags, variant magres, const char *damage[], int offmod, int defmod, - int reload, skill_t sk, int minskill) + int reload, skill_t sk) { weapon_type *wtype; - assert(minskill > 0); assert(itype && (!itype->rtype || !resource2weapon(itype->rtype))); wtype = calloc(sizeof(weapon_type), 1); if (damage) { - wtype->damage[0] = strdup(damage[0]); - wtype->damage[1] = strdup(damage[1]); + wtype->damage[0] = str_strdup(damage[0]); + wtype->damage[1] = str_strdup(damage[1]); } wtype->defmod = defmod; wtype->flags |= wflags; wtype->itype = itype; wtype->magres = magres; - wtype->minskill = minskill; wtype->offmod = offmod; wtype->reload = reload; wtype->skill = sk; @@ -315,33 +314,15 @@ armor_type *new_armortype(item_type * itype, double penalty, variant magres, return atype; } -static void pt_register(potion_type * ptype) +void it_set_appearance(item_type *itype, const char *appearance) { - ptype->itype->rtype->ptype = ptype; - ptype->next = potiontypes; - potiontypes = ptype; -} - -potion_type *new_potiontype(item_type * itype, int level) -{ - potion_type *ptype; - - assert(resource2potion(itype->rtype) == NULL); - - ptype = (potion_type *)calloc(sizeof(potion_type), 1); - ptype->itype = itype; - ptype->level = level; - pt_register(ptype); - - return ptype; -} - -void it_set_appearance(item_type *itype, const char *appearance) { assert(itype); assert(itype->rtype); if (appearance) { - itype->_appearance[0] = strdup(appearance); - itype->_appearance[1] = strcat(strcpy((char *)malloc(strlen((char *)appearance) + 3), (char *)appearance), "_p"); + char plural[32]; + itype->_appearance[0] = str_strdup(appearance); + snprintf(plural, sizeof(plural), "%s_p", appearance); + itype->_appearance[1] = str_strdup(plural); } else { itype->_appearance[0] = 0; itype->_appearance[1] = 0; @@ -375,18 +356,6 @@ const luxury_type *resource2luxury(const resource_type * rtype) #endif } -const potion_type *resource2potion(const resource_type * rtype) -{ -#ifdef AT_PTYPE - attrib *a = a_find(rtype->attribs, &at_ptype); - if (a) - return (const potion_type *)a->data.v; - return NULL; -#else - return rtype->ptype; -#endif -} - resource_type *rt_find(const char *name) { const void *match; @@ -571,7 +540,7 @@ item *i_new(const item_type * itype, int size) return i; } -const potion_type *oldpotiontype[MAX_POTIONS + 1]; +const item_type *oldpotiontype[MAX_POTIONS + 1]; /*** alte items ***/ @@ -594,7 +563,7 @@ const resource_type *get_resourcetype(resource_t type) { static struct resource_type * rtypes[MAX_RESOURCES]; const resource_type *rtype = NULL; if (update != num_resources) { - memset(rtypes, 0, sizeof(rtypes)); + memset(rtypes, 0, sizeof(resource_type *) * MAX_RESOURCES); update = num_resources; } else { @@ -629,27 +598,6 @@ int set_item(unit * u, const item_type *itype, int value) return value; } -/* t_item::flags */ -#define FL_ITEM_CURSED (1<<0) -#define FL_ITEM_NOTLOST (1<<1) -#define FL_ITEM_NOTINBAG (1<<2) /* nicht im Bag Of Holding */ -#define FL_ITEM_ANIMAL (1<<3) /* ist ein Tier */ -#define FL_ITEM_MOUNT ((1<<4) | FL_ITEM_ANIMAL) /* ist ein Reittier */ - -typedef struct t_item { - const char *name; - /* [0]: Einzahl fuer eigene; [1]: Mehrzahl fuer eigene; - * [2]: Einzahl fuer Fremde; [3]: Mehrzahl fuer Fremde */ - bool is_resource; - skill_t skill; - int minskill; - int gewicht; - int preis; - unsigned int flags; - void(*benutze_funktion) (struct region *, struct unit *, int amount, - struct order *); -} t_item; - #include "move.h" static int @@ -665,7 +613,7 @@ static int mod_dwarves_only(const unit * u, const region * r, skill_t sk, int value) { UNUSED_ARG(r); - if (u_race(u) == get_race(RC_DWARF) || (u_race(u)->flags & RCF_IRONGOLEM)) { + if (u_race(u) == get_race(RC_DWARF) || (u_race(u)->ec_flags & ECF_IRONGOLEM)) { return value; } return -118; @@ -696,7 +644,7 @@ static void init_oldpotions(void) for (p = 0; p != MAX_POTIONS; ++p) { item_type *itype = it_find(potionnames[p]); if (itype != NULL) { - oldpotiontype[p] = itype->rtype->ptype; + oldpotiontype[p] = itype; } } } @@ -744,11 +692,13 @@ void init_resources(void) int get_money(const unit * u) { const struct resource_type *rtype = get_resourcetype(R_SILVER); - const item *i = u->items; - while (i && i->type->rtype != rtype) { - i = i->next; + const item *i; + for (i = u->items; i; i = i->next) { + if (i->type->rtype == rtype) { + return i->number; + } } - return i ? i->number : 0; + return 0; } int set_money(unit * u, int v) @@ -1030,3 +980,18 @@ void register_resources(void) register_function((pf_generic)res_changehp, "changehp"); register_function((pf_generic)res_changeaura, "changeaura"); } + +void show_item(unit * u, const item_type * itype) +{ + faction * f = u->faction; + attrib *a; + + a = a_find(f->attribs, &at_showitem); + while (a && a->data.v != itype) + a = a->next; + if (!a) { + a = a_add(&f->attribs, a_new(&at_showitem)); + a->data.v = (void *)itype; + } +} + diff --git a/src/kernel/item.h b/src/kernel/item.h index 51ebcd2a1..e7bfef7cc 100644 --- a/src/kernel/item.h +++ b/src/kernel/item.h @@ -80,7 +80,6 @@ extern "C" { struct resource_mod *modifiers; /* --- pointers --- */ struct item_type *itype; - struct potion_type *ptype; struct luxury_type *ltype; struct weapon_type *wtype; struct armor_type *atype; @@ -99,6 +98,7 @@ extern "C" { #define ITF_ANIMAL 0x0010 /* an animal */ #define ITF_VEHICLE 0x0020 /* a vehicle, drawn by two animals */ #define ITF_CANUSE 0x0040 /* can be used with use_item_fun callout */ +#define ITF_POTION 0x0080 /* is a potion (for use_potion) */ /* error codes for item_type::use */ #define ECUSTOM -1 @@ -128,13 +128,6 @@ extern "C" { } luxury_type; extern luxury_type *luxurytypes; - typedef struct potion_type { - struct potion_type *next; - const item_type *itype; - int level; - } potion_type; - extern potion_type *potiontypes; - #define WMF_WALKING 0x0001 #define WMF_RIDING 0x0002 #define WMF_ANYONE 0x000F /* convenience */ @@ -187,7 +180,6 @@ extern "C" { char *damage[2]; unsigned int flags; skill_t skill; - int minskill; int offmod; int defmod; variant magres; @@ -207,7 +199,6 @@ extern "C" { const resource_type *item2resource(const item_type * i); const weapon_type *resource2weapon(const resource_type * i); - const potion_type *resource2potion(const resource_type * i); const luxury_type *resource2luxury(const resource_type * i); item **i_find(item ** pi, const item_type * it); @@ -224,7 +215,7 @@ extern "C" { /* convenience: */ item *i_change(item ** items, const item_type * it, int delta); - int i_get(const item * i, const item_type * it); + int i_get(const item * items, const item_type * it); /* creation */ resource_type *rt_get_or_create(const char *name); @@ -232,11 +223,9 @@ extern "C" { luxury_type *new_luxurytype(item_type * itype, int price); weapon_type *new_weapontype(item_type * itype, int wflags, variant magres, const char *damage[], int offmod, int defmod, int reload, - skill_t sk, int minskill); + skill_t sk); armor_type *new_armortype(item_type * itype, double penalty, variant magres, int prot, unsigned int flags); - potion_type *new_potiontype(item_type * itype, int level); - /* these constants are used with get_resourcetype. * The order of the enum is not important for stored data. @@ -286,7 +275,11 @@ extern "C" { NORESOURCE = -1 } resource_t; - extern const struct potion_type *oldpotiontype[]; + extern const struct item_type *oldpotiontype[]; + extern struct attrib_type at_showitem; /* show this potion's description */ + + void show_item(struct unit * u, const struct item_type * itype); + const struct resource_type *get_resourcetype(resource_t rt); struct item *item_spoil(const struct race *rc, int size); @@ -296,11 +289,8 @@ extern "C" { int set_money(struct unit *, int); int change_money(struct unit *, int); - extern struct attrib_type at_showitem; /* show this potion's description */ - void register_resources(void); void init_resources(void); - void init_itemtypes(void); void register_item_give(int(*foo) (struct unit *, struct unit *, const struct item_type *, int, struct order *), const char *name); diff --git a/src/kernel/item.test.c b/src/kernel/item.test.c index 89954c451..f04a22572 100644 --- a/src/kernel/item.test.c +++ b/src/kernel/item.test.c @@ -18,7 +18,7 @@ static void test_resourcename_no_appearance(CuTest *tc) { const resource_type *rtype; - test_cleanup(); + test_setup(); init_resources(); /* creates R_SILVER */ rtype = get_resourcetype(R_SILVER); assert(rtype && rtype->itype); @@ -28,13 +28,13 @@ static void test_resourcename_no_appearance(CuTest *tc) { CuAssertStrEquals(tc, "money_p", resourcename(rtype, NMF_PLURAL)); CuAssertStrEquals(tc, "money", resourcename(rtype, NMF_APPEARANCE)); CuAssertStrEquals(tc, "money_p", resourcename(rtype, NMF_APPEARANCE | NMF_PLURAL)); - test_cleanup(); + test_teardown(); } static void test_resourcename_with_appearance(CuTest *tc) { item_type *itype; - test_cleanup(); + test_setup(); itype = it_get_or_create(rt_get_or_create("foo")); assert(itype && itype->rtype); it_set_appearance(itype, "bar"); @@ -42,7 +42,7 @@ static void test_resourcename_with_appearance(CuTest *tc) { CuAssertStrEquals(tc, "foo_p", resourcename(itype->rtype, NMF_PLURAL)); CuAssertStrEquals(tc, "bar", resourcename(itype->rtype, NMF_APPEARANCE)); CuAssertStrEquals(tc, "bar_p", resourcename(itype->rtype, NMF_APPEARANCE | NMF_PLURAL)); - test_cleanup(); + test_teardown(); } static void test_uchange(CuTest * tc, unit * u, const resource_type * rtype) { @@ -74,9 +74,10 @@ void test_change_item(CuTest * tc) test_create_itemtype("iron"); init_resources(); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); test_uchange(tc, u, get_resourcetype(R_IRON)); - test_cleanup(); + test_log_stderr(1); + test_teardown(); } void test_resource_type(CuTest * tc) @@ -92,7 +93,7 @@ void test_resource_type(CuTest * tc) itype = test_create_itemtype("herp"); CuAssertPtrEquals(tc, itype->rtype, rt_find("herp")); - test_cleanup(); + test_teardown(); } void test_finditemtype(CuTest * tc) @@ -106,7 +107,7 @@ void test_finditemtype(CuTest * tc) locale_setstring(lang, "horse", "Pferd"); itype = test_create_itemtype("horse"); CuAssertPtrEquals(tc, (void *)itype, (void *)finditemtype("Pferd", lang)); - test_cleanup(); + test_teardown(); } void test_findresourcetype(CuTest * tc) @@ -126,7 +127,7 @@ void test_findresourcetype(CuTest * tc) CuAssertPtrEquals(tc, (void*)itype->rtype, (void*)findresourcetype("Holz", lang)); CuAssertPtrEquals(tc, (void *)rt_find("peasant"), (void *)findresourcetype("Bauer", lang)); - test_cleanup(); + test_teardown(); } #include @@ -151,7 +152,7 @@ static void test_fix_demand(CuTest *tc) { CuAssertPtrNotNull(tc, r->land->demands); CuAssertPtrNotNull(tc, r->land->demands->next); CuAssertPtrNotNull(tc, r_luxury(r)); - test_cleanup(); + test_teardown(); } static void test_core_resources(CuTest *tc) { @@ -170,7 +171,7 @@ static void test_core_resources(CuTest *tc) { CuAssertPtrEquals(tc, 0, rtype->itype); CuAssertPtrNotNull(tc, rtype = rt_find("aura")); CuAssertPtrEquals(tc, 0, rtype->itype); - test_cleanup(); + test_teardown(); } static void test_get_resource(CuTest *tc) { @@ -188,7 +189,7 @@ static void test_get_resource(CuTest *tc) { rtype = rt_get_or_create("catapult"); CuAssertPtrEquals(tc, rtype, rt_find("catapult")); CuAssertStrEquals(tc, "catapult", rtype->_name); - test_cleanup(); + test_teardown(); } CuSuite *get_item_suite(void) diff --git a/src/kernel/messages.c b/src/kernel/messages.c index f2a175269..03883f127 100644 --- a/src/kernel/messages.c +++ b/src/kernel/messages.c @@ -32,6 +32,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include #include #include #include @@ -91,7 +92,7 @@ struct message *msg_feedback(const struct unit *u, struct order *ord, log_warning("trying to create message of unknown type \"%s\"\n", name); if (!mt_find("missing_feedback")) { mt_register(mt_new_va("missing_feedback", "unit:unit", - "region:region", "command:order", "name:string", 0)); + "region:region", "command:order", "name:string", NULL)); } return msg_message("missing_feedback", "name unit region command", name, u, u->region, ord); @@ -147,6 +148,28 @@ struct message *msg_feedback(const struct unit *u, struct order *ord, return msg_create(mtype, args); } +static int missing_message_mode; + +void message_handle_missing(int mode) { + missing_message_mode = mode; +} + +static message *missing_message(const char *name) { + if (missing_message_mode == MESSAGE_MISSING_ERROR) { + log_error("trying to create undefined message of type \"%s\"\n", name); + } + else if (missing_message_mode == MESSAGE_MISSING_REPLACE) { + log_warning("trying to create undefined message of type \"%s\"\n", name); + if (strcmp(name, "missing_message") != 0) { + if (!mt_find("missing_message")) { + mt_register(mt_new_va("missing_message", "name:string", NULL)); + } + return msg_message("missing_message", "name", name); + } + } + return NULL; +} + message *msg_message(const char *name, const char *sig, ...) /* msg_message("oops_error", "unit region command", u, r, cmd) */ { @@ -159,14 +182,7 @@ message *msg_message(const char *name, const char *sig, ...) memset(args, 0, sizeof(args)); if (!mtype) { - log_warning("trying to create message of unknown type \"%s\"\n", name); - if (strcmp(name, "missing_message") != 0) { - if (!mt_find("missing_message")) { - mt_register(mt_new_va("missing_message", "name:string", 0)); - } - return msg_message("missing_message", "name", name); - } - return NULL; + return missing_message(name); } va_start(vargs, sig); @@ -291,7 +307,7 @@ void free_messagelist(mlist *msgs) message *add_message(message_list ** pm, message * m) { assert(m && m->type); - if (!lomem && m != NULL) { + if (m != NULL) { struct mlist *mnew = malloc(sizeof(struct mlist)); if (*pm == NULL) { *pm = malloc(sizeof(message_list)); diff --git a/src/kernel/messages.h b/src/kernel/messages.h index 58558072d..723ed2d01 100644 --- a/src/kernel/messages.h +++ b/src/kernel/messages.h @@ -46,6 +46,12 @@ extern "C" { int level; } msglevel; +#define MESSAGE_MISSING_IGNORE 0 +#define MESSAGE_MISSING_ERROR 1 +#define MESSAGE_MISSING_REPLACE 2 + + void message_handle_missing(int mode); + struct message *msg_message(const char *name, const char *sig, ...); struct message *msg_feedback(const struct unit *, struct order *cmd, const char *name, const char *sig, ...); @@ -54,8 +60,8 @@ extern "C" { void addmessage(struct region *r, struct faction *f, const char *s, msg_t mtype, int level); - struct mlist ** merge_messages(message_list *mlist, message_list *append); - void split_messages(message_list *mlist, struct mlist **split); + struct mlist ** merge_messages(message_list *ml, message_list *append); + void split_messages(message_list *ml, struct mlist **split); #define ADDMSG(msgs, mcreate) { message * mx = mcreate; if (mx) { assert(mx->refcount>=1); add_message(msgs, mx); msg_release(mx); } } diff --git a/src/kernel/messages.test.c b/src/kernel/messages.test.c index a26530895..4afe25518 100644 --- a/src/kernel/messages.test.c +++ b/src/kernel/messages.test.c @@ -9,18 +9,22 @@ void test_missing_message(CuTest *tc) { message *msg; + + test_setup(); + message_handle_missing(MESSAGE_MISSING_REPLACE); msg = msg_message("unknown", "unit", NULL); CuAssertPtrNotNull(tc, msg); CuAssertPtrNotNull(tc, msg->type); CuAssertStrEquals(tc, msg->type->name, "missing_message"); msg_release(msg); + test_teardown(); } void test_message(CuTest *tc) { message *msg; message_type *mtype = mt_new("custom", NULL); - test_cleanup(); + test_setup(); mt_register(mtype); CuAssertPtrEquals(tc, mtype, (void *)mt_find("custom")); CuAssertIntEquals(tc, 0, mtype->nparameters); @@ -37,7 +41,7 @@ void test_message(CuTest *tc) { msg_release(msg); CuAssertIntEquals(tc, 1, msg->refcount); msg_release(msg); - test_cleanup(); + test_teardown(); } static void test_merge_split(CuTest *tc) { @@ -46,7 +50,7 @@ static void test_merge_split(CuTest *tc) { message_type *mtype = mt_new("custom", NULL); message *msg; - test_cleanup(); + test_setup(); mt_register(mtype); add_message(&mlist, msg = msg_message(mtype->name, "")); msg_release(msg); @@ -68,7 +72,7 @@ static void test_merge_split(CuTest *tc) { free(mlist); free_messagelist(append->begin); free(append); - test_cleanup(); + test_teardown(); } static void test_noerror(CuTest *tc) { @@ -83,7 +87,7 @@ static void test_noerror(CuTest *tc) { CuAssertTrue(tc, !is_persistent(u->thisorder)); CuAssertPtrEquals(tc, NULL, msg_error(u, u->thisorder, 100)); CuAssertPtrEquals(tc, NULL, msg_feedback(u, u->thisorder, "error_unit_not_found", NULL)); - test_cleanup(); + test_teardown(); } CuSuite *get_messages_suite(void) { diff --git a/src/kernel/order.c b/src/kernel/order.c index a48825333..8defd05c9 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -14,14 +14,17 @@ #include #include "order.h" +#include "orderdb.h" #include "skill.h" #include "keyword.h" #include -#include #include #include #include +#include + +#include /* libc includes */ #include @@ -31,31 +34,7 @@ #include # define ORD_KEYWORD(ord) (keyword_t)((ord)->command & 0xFFFF) -# define ORD_LOCALE(ord) locale_array[(ord)->data->_lindex]->lang -# define ORD_STRING(ord) (ord)->data->_str - -typedef struct locale_data { - struct order_data *short_orders; - struct order_data *study_orders[MAXSKILLS]; - const struct locale *lang; -} locale_data; - -static struct locale_data *locale_array[MAXLOCALES]; - -typedef struct order_data { - const char *_str; - int _refcount; - int _lindex; -} order_data; - -static void release_data(order_data * data) -{ - if (data) { - if (--data->_refcount == 0) { - free(data); - } - } -} +# define OD_STRING(odata) ((odata) ? (odata)->_str : NULL) void replace_order(order ** dlist, order * orig, const order * src) { @@ -64,7 +43,7 @@ void replace_order(order ** dlist, order * orig, const order * src) assert(dlist); while (*dlist != NULL) { order *dst = *dlist; - if (dst->data == orig->data) { + if (dst->id == orig->id) { order *cpy = copy_order(src); *dlist = cpy; cpy->next = dst->next; @@ -87,71 +66,92 @@ keyword_t getkeyword(const order * ord) * This is the inverse function to the parse_order command. Note that * keywords are expanded to their full length. */ -char* get_command(const order *ord, char *sbuffer, size_t size) { - char *bufp = sbuffer; - const char *text = ORD_STRING(ord); +char* get_command(const order *ord, const struct locale *lang, char *sbuffer, size_t size) { + order_data *od = NULL; + const char * text; keyword_t kwd = ORD_KEYWORD(ord); - int bytes; + sbstring sbs; + sbs_init(&sbs, sbuffer, size); if (ord->command & CMD_QUIET) { - if (size > 0) { - *bufp++ = '!'; - --size; - } - else { - WARN_STATIC_BUFFER(); - } + sbs_strcpy(&sbs, "!"); } if (ord->command & CMD_PERSIST) { - if (size > 0) { - *bufp++ = '@'; - --size; - } - else { - WARN_STATIC_BUFFER(); - } + sbs_strcat(&sbs, "@"); + } + + if (ord->id < 0) { + skill_t sk = (skill_t)(100+ord->id); + assert(kwd == K_STUDY && sk != SK_MAGIC && sk < MAXSKILLS); + text = skillname(sk, lang); + } else { + od = odata_load(ord->id); + text = OD_STRING(od); } if (kwd != NOKEYWORD) { - const struct locale *lang = ORD_LOCALE(ord); - if (size > 0) { - const char *str = (const char *)LOC(lang, keyword(kwd)); - assert(str); - if (text) --size; - bytes = (int)strlcpy(bufp, str, size); - if (wrptr(&bufp, &size, bytes) != 0) { - WARN_STATIC_BUFFER(); - } - if (text) *bufp++ = ' '; - } - else { - WARN_STATIC_BUFFER(); + const char *str = (const char *)LOC(lang, keyword(kwd)); + assert(str); + sbs_strcat(&sbs, str); + if (text) { + sbs_strcat(&sbs, " "); } } if (text) { - bytes = (int)strlcpy(bufp, (const char *)text, size); - if (wrptr(&bufp, &size, bytes) != 0) { - WARN_STATIC_BUFFER(); - if (bufp - sbuffer >= 6) { - bufp -= 6; - while (bufp > sbuffer && (*bufp & 0x80) != 0) { - ++size; - --bufp; - } - memcpy(bufp, "[...]", 6); /* TODO: make sure this only happens in eval_command */ - bufp += 6; - } - } + sbs_strcat(&sbs, text); + } + if (od) { + odata_release(od); } - if (size > 0) *bufp = 0; return sbuffer; } +int stream_order(struct stream *out, const struct order *ord, const struct locale *lang, bool escape) +{ + const char *str, *text; + order_data *od = NULL; + keyword_t kwd = ORD_KEYWORD(ord); + + if (ord->command & CMD_QUIET) { + swrite("!", 1, 1, out); + } + if (ord->command & CMD_PERSIST) { + swrite("@", 1, 1, out); + } + + if (ord->id < 0) { + skill_t sk = (skill_t)(100 + ord->id); + assert(kwd == K_STUDY && sk != SK_MAGIC && sk < MAXSKILLS); + text = skillname(sk, lang); + } + else { + od = odata_load(ord->id); + text = OD_STRING(od); + } + if (kwd != NOKEYWORD) { + str = (const char *)LOC(lang, keyword(kwd)); + assert(str); + swrite(str, 1, strlen(str), out); + } + + if (text) { + char obuf[1024]; + swrite(" ", 1, 1, out); + if (escape) { + text = str_escape(text, obuf, sizeof(obuf)); + } + swrite(text, 1, strlen(text), out); + } + if (od) { + odata_release(od); + } + + return 0; +} + void free_order(order * ord) { if (ord != NULL) { assert(ord->next == 0); - - release_data(ord->data); free(ord); } } @@ -162,8 +162,7 @@ order *copy_order(const order * src) order *ord = (order *)malloc(sizeof(order)); ord->next = NULL; ord->command = src->command; - ord->data = src->data; - ++ord->data->_refcount; + ord->id = src->id; return ord; } return NULL; @@ -187,129 +186,37 @@ void free_orders(order ** olist) } } -static char *mkdata(order_data **pdata, size_t len, int lindex, const char *str) +static int create_data(keyword_t kwd, const char *s, + const struct locale *lang) { order_data *data; - char *result; - data = malloc(sizeof(order_data) + len + 1); - result = (char *)(data + 1); - data->_lindex = lindex; - data->_refcount = 0; - data->_str = 0; - data->_str = (len > 0) ? result : 0; - if (str) strcpy(result, str); - if (pdata) *pdata = data; - return result; -} + int id; -static order_data *create_data(keyword_t kwd, const char *sptr, int lindex) -{ - const char *s = sptr; - order_data *data; - const struct locale *lang = locale_array[lindex]->lang; + assert(kwd!=NOKEYWORD); - if (kwd != NOKEYWORD) - s = (*sptr) ? sptr : NULL; - - /* learning, only one order_data per skill required */ - if (kwd == K_STUDY) { - skill_t sk = get_skill(parse_token_depr(&sptr), lang); - switch (sk) { - case NOSKILL: /* fehler */ - break; - case SK_MAGIC: /* kann parameter haben */ - if (*sptr != 0) - break; - default: /* nur skill als Parameter, keine extras */ - data = locale_array[lindex]->study_orders[sk]; - if (data == NULL) { - const char *skname = skillname(sk, lang); - const char *spc = strchr(skname, ' '); - size_t len = strlen(skname); - char *dst = mkdata(&data, len + (spc ? 3 : 0), lindex, spc ? 0 : skname); - locale_array[lindex]->study_orders[sk] = data; - if (spc) { - dst[0] = '\"'; - memcpy(dst + 1, skname, len); - dst[len + 1] = '\"'; - dst[len + 2] = '\0'; - } - data->_refcount = 1; - } - ++data->_refcount; - return data; - } - } - - /* orders with no parameter, only one order_data per order required */ - else if (kwd != NOKEYWORD && *sptr == 0) { - data = locale_array[lindex]->short_orders; - if (data == NULL) { - mkdata(&data, 0, lindex, 0); - data->_refcount = 1; - locale_array[lindex]->short_orders = data; - } - ++data->_refcount; - return data; - } - mkdata(&data, s ? strlen(s) : 0, lindex, s); - data->_refcount = 1; - return data; -} - -static void clear_localedata(int lindex) { - int i; - release_data(locale_array[lindex]->short_orders); - locale_array[lindex]->short_orders = NULL; - for (i = 0; i != MAXSKILLS; ++i) { - release_data(locale_array[lindex]->study_orders[i]); - locale_array[lindex]->study_orders[i] = 0; + if (!s || *s == 0) { + return 0; } - locale_array[lindex]->lang = 0; -} - -void close_orders(void) { - int i; - for (i = 0; i != MAXLOCALES; ++i) { - if (locale_array[i]){ - clear_localedata(i); - free(locale_array[i]); - locale_array[i] = 0; + if (kwd==K_STUDY) { + const char * sptr = s; + skill_t sk = get_skill(parse_token_depr(&sptr), lang); + if (sk != SK_MAGIC && sk != NOSKILL) { + return ((int)sk)-100; } } + /* TODO: between mkdata and odata_release, this object is very + * short-lived. */ + odata_create(&data, strlen(s), s); + id = odata_save(data); + odata_release(data); + return id; } -static order *create_order_i(order *ord, keyword_t kwd, const char *sptr, bool persistent, +static void create_order_i(order *ord, keyword_t kwd, const char *sptr, bool persistent, bool noerror, const struct locale *lang) { - int lindex; - assert(ord); - if (kwd == NOKEYWORD || keyword_disabled(kwd)) { - log_error("trying to create an order for disabled keyword %s.", keyword(kwd)); - return NULL; - } - - /* if this is just nonsense, then we skip it. */ - if (lomem) { - switch (kwd) { - case K_KOMMENTAR: - case NOKEYWORD: - return NULL; - default: - break; - } - } - - lindex = locale_index(lang); - assert(lindex < MAXLOCALES); - if (!locale_array[lindex]) { - locale_array[lindex] = (locale_data *)calloc(1, sizeof(locale_data)); - } - else if (locale_array[lindex]->lang != lang) { - clear_localedata(lindex); - } - locale_array[lindex]->lang = lang; + assert(kwd != NOKEYWORD && !keyword_disabled(kwd)); ord->command = (int)kwd; if (persistent) ord->command |= CMD_PERSIST; @@ -317,9 +224,8 @@ static order *create_order_i(order *ord, keyword_t kwd, const char *sptr, bool p ord->next = NULL; while (isspace(*(unsigned char *)sptr)) ++sptr; - ord->data = create_data(kwd, sptr, lindex); - return ord; + ord->id = create_data(kwd, sptr, lang); } order *create_order(keyword_t kwd, const struct locale * lang, @@ -328,56 +234,53 @@ order *create_order(keyword_t kwd, const struct locale * lang, order *ord; char zBuffer[DISPLAYSIZE]; if (params) { - char *bufp = zBuffer; - int bytes; - size_t size = sizeof(zBuffer) - 1; + sbstring sbs; va_list marker; + char *tok; assert(lang); va_start(marker, params); + sbs_init(&sbs, zBuffer, sizeof(zBuffer)); while (*params) { - if (*params == '%') { - int i; - const char *s; - ++params; - switch (*params) { + int i; + const char *s; + tok = strchr(params, '%'); + if (tok) { + if (tok != params) { + sbs_strncat(&sbs, params, tok - params); + } + switch (tok[1]) { case 's': s = va_arg(marker, const char *); assert(s); - bytes = (int)strlcpy(bufp, s, size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); + sbs_strcat(&sbs, s); break; case 'd': i = va_arg(marker, int); - bytes = (int)strlcpy(bufp, itoa10(i), size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); + sbs_strcat(&sbs, itoa10(i)); break; case 'i': i = va_arg(marker, int); - bytes = (int)strlcpy(bufp, itoa36(i), size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); + sbs_strcat(&sbs, itoa36(i)); break; default: assert(!"unknown format-character in create_order"); } + params = tok + 2; } - else if (size > 0) { - *bufp++ = *params; - --size; + else { + sbs_strcat(&sbs, params); + break; } - ++params; } va_end(marker); - *bufp = 0; } else { zBuffer[0] = 0; } ord = (order *)malloc(sizeof(order)); - return create_order_i(ord, kwd, zBuffer, false, false, lang); + create_order_i(ord, kwd, zBuffer, false, false, lang); + return ord; } order *parse_order(const char *s, const struct locale * lang) @@ -409,7 +312,8 @@ order *parse_order(const char *s, const struct locale * lang) } if (kwd != NOKEYWORD) { order *ord = (order *)malloc(sizeof(order)); - return create_order_i(ord, kwd, sptr, persistent, noerror, lang); + create_order_i(ord, kwd, sptr, persistent, noerror, lang); + return ord; } } return NULL; @@ -565,7 +469,7 @@ bool is_silent(const order * ord) return (ord->command & CMD_QUIET) != 0; } -char *write_order(const order * ord, char *buffer, size_t size) +char *write_order(const order * ord, const struct locale *lang, char *buffer, size_t size) { if (ord == 0) { buffer[0] = 0; @@ -573,12 +477,14 @@ char *write_order(const order * ord, char *buffer, size_t size) else { keyword_t kwd = ORD_KEYWORD(ord); if (kwd == NOKEYWORD) { - const char *text = ORD_STRING(ord); - if (text) strlcpy(buffer, (const char *)text, size); + order_data *od = odata_load(ord->id); + const char *text = OD_STRING(od); + if (text) str_strlcpy(buffer, (const char *)text, size); else buffer[0] = 0; + odata_release(od); } else { - get_command(ord, buffer, size); + get_command(ord, lang, buffer, size); } } return buffer; @@ -591,9 +497,54 @@ void push_order(order ** ordp, order * ord) *ordp = ord; } -keyword_t init_order(const struct order *ord) +static order_data *parser_od; + +keyword_t init_order(const struct order *ord, const struct locale *lang) { - assert(ord && ord->data); - init_tokens_str(ord->data->_str); - return ORD_KEYWORD(ord); + if (!ord) { + odata_release(parser_od); + parser_od = NULL; + return NOKEYWORD; + } + else { + keyword_t kwd = ORD_KEYWORD(ord); + if (parser_od) { + /* TODO: warning */ + odata_release(parser_od); + parser_od = NULL; + } + if (ord->id < 0) { + skill_t sk = (skill_t)(100 + ord->id); + assert(sk < MAXSKILLS); + assert(lang); + assert(kwd == K_STUDY); + init_tokens_str(skillname(sk, lang)); + } + else { + const char *str; + parser_od = odata_load(ord->id); + if (parser_od) { + odata_addref(parser_od); + } + str = OD_STRING(parser_od); + init_tokens_ex(str, parser_od, (void(*)(void *))odata_release); + } + return kwd; + } +} + +keyword_t init_order_depr(const struct order *ord) +{ + if (ord) { + keyword_t kwd = ORD_KEYWORD(ord); + assert(kwd != K_STUDY); + } + return init_order(ord, NULL); +} + +void close_orders(void) { + if (parser_od) { + (void)init_order(NULL, NULL); + } } + diff --git a/src/kernel/order.h b/src/kernel/order.h index b9d235c88..02e03ff56 100644 --- a/src/kernel/order.h +++ b/src/kernel/order.h @@ -21,6 +21,9 @@ extern "C" { #endif + struct locale; + struct stream; + /* Encapsulation of an order * * This structure contains one order given by a unit. These used to be @@ -30,8 +33,6 @@ extern "C" { * implemented yet) saving approx. 50% of all string-related memory. */ - struct order_data; - #define CMD_QUIET 0x010000 #define CMD_PERSIST 0x020000 #define CMD_DEFAULT 0x040000 @@ -39,7 +40,7 @@ extern "C" { typedef struct order { struct order *next; /* do not access this data: */ - struct order_data *data; + int id; int command; } order; @@ -59,15 +60,19 @@ extern "C" { /* access functions for orders */ keyword_t getkeyword(const order * ord); void set_order(order ** destp, order * src); - char* get_command(const order *ord, char *buffer, size_t size); + char* get_command(const order *ord, const struct locale *lang, + char *buffer, size_t size); bool is_persistent(const order * ord); bool is_silent(const order * ord); bool is_exclusive(const order * ord); bool is_repeated(keyword_t kwd); bool is_long(keyword_t kwd); - char *write_order(const order * ord, char *buffer, size_t size); - keyword_t init_order(const struct order *ord); + char *write_order(const order * ord, const struct locale *lang, + char *buffer, size_t size); + int stream_order(struct stream *out, const struct order *ord, const struct locale *lang, bool escape); + keyword_t init_order_depr(const struct order *ord); + keyword_t init_order(const struct order *ord, const struct locale *lang); void close_orders(void); diff --git a/src/kernel/order.test.c b/src/kernel/order.test.c index 71938ca7e..74679db6e 100644 --- a/src/kernel/order.test.c +++ b/src/kernel/order.test.c @@ -2,6 +2,8 @@ #include #include "order.h" +#include + #include #include @@ -20,12 +22,12 @@ static void test_create_order(CuTest *tc) { ord = create_order(K_MOVE, lang, "NORTH"); CuAssertPtrNotNull(tc, ord); CuAssertIntEquals(tc, K_MOVE, getkeyword(ord)); - CuAssertStrEquals(tc, "move NORTH", get_command(ord, cmd, sizeof(cmd))); + CuAssertStrEquals(tc, "move NORTH", get_command(ord, lang, cmd, sizeof(cmd))); - CuAssertIntEquals(tc, K_MOVE, init_order(ord)); + CuAssertIntEquals(tc, K_MOVE, init_order_depr(ord)); CuAssertStrEquals(tc, "NORTH", getstrtoken()); free_order(ord); - test_cleanup(); + test_teardown(); } static void test_parse_order(CuTest *tc) { @@ -40,48 +42,48 @@ static void test_parse_order(CuTest *tc) { CuAssertPtrNotNull(tc, ord); CuAssertIntEquals(tc, K_MOVE, ord->command); CuAssertIntEquals(tc, K_MOVE, getkeyword(ord)); - CuAssertStrEquals(tc, "move NORTH", get_command(ord, cmd, sizeof(cmd))); + CuAssertStrEquals(tc, "move NORTH", get_command(ord, lang, cmd, sizeof(cmd))); - CuAssertIntEquals(tc, K_MOVE, init_order(ord)); + CuAssertIntEquals(tc, K_MOVE, init_order_depr(ord)); CuAssertStrEquals(tc, "NORTH", getstrtoken()); free_order(ord); ord = parse_order("!MOVE NORTH", lang); CuAssertPtrNotNull(tc, ord); - CuAssertPtrNotNull(tc, ord->data); + CuAssertTrue(tc, ord->id > 0); CuAssertIntEquals(tc, K_MOVE, getkeyword(ord)); CuAssertIntEquals(tc, K_MOVE | CMD_QUIET, ord->command); free_order(ord); ord = parse_order("@MOVE NORTH", lang); CuAssertPtrNotNull(tc, ord); - CuAssertPtrNotNull(tc, ord->data); + CuAssertTrue(tc, ord->id > 0); CuAssertIntEquals(tc, K_MOVE, getkeyword(ord)); CuAssertIntEquals(tc, K_MOVE | CMD_PERSIST, ord->command); free_order(ord); ord = parse_order("!@MOVE NORTH", lang); CuAssertPtrNotNull(tc, ord); - CuAssertPtrNotNull(tc, ord->data); + CuAssertTrue(tc, ord->id > 0); CuAssertIntEquals(tc, K_MOVE, getkeyword(ord)); CuAssertIntEquals(tc, K_MOVE | CMD_PERSIST | CMD_QUIET, ord->command); free_order(ord); ord = parse_order("@!MOVE NORTH", lang); CuAssertPtrNotNull(tc, ord); - CuAssertPtrNotNull(tc, ord->data); + CuAssertTrue(tc, ord->id > 0); CuAssertIntEquals(tc, K_MOVE, getkeyword(ord)); CuAssertIntEquals(tc, K_MOVE | CMD_PERSIST | CMD_QUIET, ord->command); free_order(ord); ord = parse_order(" !@MOVE NORTH", lang); CuAssertPtrNotNull(tc, ord); - CuAssertPtrNotNull(tc, ord->data); + CuAssertTrue(tc, ord->id > 0); CuAssertIntEquals(tc, K_MOVE, getkeyword(ord)); CuAssertIntEquals(tc, K_MOVE | CMD_PERSIST | CMD_QUIET, ord->command); free_order(ord); - test_cleanup(); + test_teardown(); } static void test_parse_make(CuTest *tc) { @@ -89,7 +91,7 @@ static void test_parse_make(CuTest *tc) { order *ord; struct locale * lang; - test_cleanup(); + test_setup(); lang = get_or_create_locale("en"); locale_setstring(lang, keyword(K_MAKE), "MAKE"); @@ -98,12 +100,12 @@ static void test_parse_make(CuTest *tc) { ord = parse_order("M hurrdurr", lang); CuAssertPtrNotNull(tc, ord); CuAssertIntEquals(tc, K_MAKE, getkeyword(ord)); - CuAssertStrEquals(tc, "MAKE hurrdurr", get_command(ord, cmd, sizeof(cmd))); + CuAssertStrEquals(tc, "MAKE hurrdurr", get_command(ord, lang, cmd, sizeof(cmd))); - CuAssertIntEquals(tc, K_MAKE, init_order(ord)); + CuAssertIntEquals(tc, K_MAKE, init_order_depr(ord)); CuAssertStrEquals(tc, "hurrdurr", getstrtoken()); free_order(ord); - test_cleanup(); + test_teardown(); } static void test_parse_make_temp(CuTest *tc) { @@ -111,7 +113,7 @@ static void test_parse_make_temp(CuTest *tc) { order *ord; struct locale * lang; - test_cleanup(); + test_setup(); lang = get_or_create_locale("en"); locale_setstring(lang, keyword(K_MAKE), "MAKE"); locale_setstring(lang, keyword(K_MAKETEMP), "MAKETEMP"); @@ -121,12 +123,12 @@ static void test_parse_make_temp(CuTest *tc) { ord = parse_order("M T herp", lang); CuAssertPtrNotNull(tc, ord); CuAssertIntEquals(tc, K_MAKETEMP, getkeyword(ord)); - CuAssertStrEquals(tc, "MAKETEMP herp", get_command(ord, cmd, sizeof(cmd))); + CuAssertStrEquals(tc, "MAKETEMP herp", get_command(ord, lang, cmd, sizeof(cmd))); - CuAssertIntEquals(tc, K_MAKETEMP, init_order(ord)); + CuAssertIntEquals(tc, K_MAKETEMP, init_order_depr(ord)); CuAssertStrEquals(tc, "herp", getstrtoken()); free_order(ord); - test_cleanup(); + test_teardown(); } static void test_parse_maketemp(CuTest *tc) { @@ -134,7 +136,7 @@ static void test_parse_maketemp(CuTest *tc) { order *ord; struct locale * lang; - test_cleanup(); + test_setup(); lang = get_or_create_locale("en"); locale_setstring(lang, keyword(K_MAKE), "MAKE"); @@ -144,27 +146,27 @@ static void test_parse_maketemp(CuTest *tc) { ord = parse_order("MAKET herp", lang); CuAssertPtrNotNull(tc, ord); - CuAssertStrEquals(tc, "MAKETEMP herp", get_command(ord, cmd, sizeof(cmd))); + CuAssertStrEquals(tc, "MAKETEMP herp", get_command(ord, lang, cmd, sizeof(cmd))); CuAssertIntEquals(tc, K_MAKETEMP, getkeyword(ord)); - CuAssertIntEquals(tc, K_MAKETEMP, init_order(ord)); + CuAssertIntEquals(tc, K_MAKETEMP, init_order_depr(ord)); CuAssertStrEquals(tc, "herp", getstrtoken()); free_order(ord); - test_cleanup(); + test_teardown(); } static void test_init_order(CuTest *tc) { order *ord; struct locale * lang; - test_cleanup(); + test_setup(); lang = get_or_create_locale("en"); ord = create_order(K_MAKETEMP, lang, "hurr durr"); - CuAssertIntEquals(tc, K_MAKETEMP, init_order(ord)); + CuAssertIntEquals(tc, K_MAKETEMP, init_order_depr(ord)); CuAssertStrEquals(tc, "hurr", getstrtoken()); CuAssertStrEquals(tc, "durr", getstrtoken()); free_order(ord); - test_cleanup(); + test_teardown(); } static void test_getstrtoken(CuTest *tc) { @@ -189,7 +191,7 @@ static void test_replace_order(CuTest *tc) { order *orders = 0, *orig, *repl; struct locale * lang; - test_cleanup(); + test_setup(); lang = test_create_locale(); orig = create_order(K_MAKE, lang, NULL); repl = create_order(K_ALLY, lang, NULL); @@ -202,7 +204,7 @@ static void test_replace_order(CuTest *tc) { CuAssertIntEquals(tc, getkeyword(repl), getkeyword(orders)); free_order(orders); free_order(repl); - test_cleanup(); + test_teardown(); } static void test_get_command(CuTest *tc) { @@ -213,15 +215,15 @@ static void test_get_command(CuTest *tc) { test_setup(); lang = test_create_locale(); ord = create_order(K_MAKE, lang, "iron"); - CuAssertStrEquals(tc, "make iron", get_command(ord, buf, sizeof(buf))); + CuAssertStrEquals(tc, "make iron", get_command(ord, lang, buf, sizeof(buf))); ord->command |= CMD_QUIET; - CuAssertStrEquals(tc, "!make iron", get_command(ord, buf, sizeof(buf))); + CuAssertStrEquals(tc, "!make iron", get_command(ord, lang, buf, sizeof(buf))); ord->command |= CMD_PERSIST; - CuAssertStrEquals(tc, "!@make iron", get_command(ord, buf, sizeof(buf))); + CuAssertStrEquals(tc, "!@make iron", get_command(ord, lang, buf, sizeof(buf))); ord->command = K_MAKE | CMD_PERSIST; - CuAssertStrEquals(tc, "@make iron", get_command(ord, buf, sizeof(buf))); + CuAssertStrEquals(tc, "@make iron", get_command(ord, lang, buf, sizeof(buf))); free_order(ord); - test_cleanup(); + test_teardown(); } static void test_is_persistent(CuTest *tc) { @@ -261,7 +263,7 @@ static void test_is_persistent(CuTest *tc) { CuAssertIntEquals(tc, K_KOMMENTAR, ord->command); free_order(ord); - test_cleanup(); + test_teardown(); } @@ -290,12 +292,50 @@ static void test_is_silent(CuTest *tc) { CuAssertIntEquals(tc, K_KOMMENTAR, ord->command); free_order(ord); - test_cleanup(); + test_teardown(); } + +static void test_study_orders(CuTest *tc) { + order *ord; + struct locale *lang; + const char *s; + char token[16]; + + test_setup(); + lang = test_create_locale(); + + ord = create_order(K_STUDY, lang, skillname(SK_CROSSBOW, lang)); + CuAssertIntEquals(tc, K_STUDY, getkeyword(ord)); + CuAssertIntEquals(tc, K_STUDY, init_order(ord, lang)); + s = gettoken(token, sizeof(token)); + CuAssertStrEquals(tc, skillname(SK_CROSSBOW, lang), s); + CuAssertPtrEquals(tc, NULL, (void *)getstrtoken()); + free_order(ord); + + ord = create_order(K_STUDY, lang, skillname(SK_MAGIC, lang)); + CuAssertIntEquals(tc, K_STUDY, getkeyword(ord)); + CuAssertIntEquals(tc, K_STUDY, init_order(ord, lang)); + s = gettoken(token, sizeof(token)); + CuAssertStrEquals(tc, skillname(SK_MAGIC, lang), s); + CuAssertPtrEquals(tc, NULL, (void *)getstrtoken()); + free_order(ord); + + ord = create_order(K_STUDY, lang, "%s 100", skillname(SK_MAGIC, lang)); + CuAssertIntEquals(tc, K_STUDY, getkeyword(ord)); + CuAssertIntEquals(tc, K_STUDY, init_order(ord, lang)); + s = gettoken(token, sizeof(token)); + CuAssertStrEquals(tc, skillname(SK_MAGIC, lang), s); + CuAssertIntEquals(tc, 100, getint()); + free_order(ord); + + test_teardown(); +} + CuSuite *get_order_suite(void) { CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_create_order); + SUITE_ADD_TEST(suite, test_study_orders); SUITE_ADD_TEST(suite, test_parse_order); SUITE_ADD_TEST(suite, test_parse_make); SUITE_ADD_TEST(suite, test_parse_make_temp); diff --git a/src/kernel/orderdb.c b/src/kernel/orderdb.c new file mode 100644 index 000000000..b30131be4 --- /dev/null +++ b/src/kernel/orderdb.c @@ -0,0 +1,51 @@ +#include +#include "database.h" +#include "orderdb.h" + +#include + +#include + +#include +#include +#include + +void odata_create(order_data **pdata, size_t len, const char *str) +{ + order_data *data; + char *result; + + assert(pdata); + data = malloc(sizeof(order_data) + len + 1); + data->_refcount = 1; + result = (char *)(data + 1); + data->_str = (len > 0) ? result : NULL; + if (str) { + strcpy(result, str); + } + *pdata = data; +} + +void odata_release(order_data * od) +{ + if (od) { + if (--od->_refcount == 0) { + free(od); + } + } +} + +void odata_addref(order_data *od) +{ + ++od->_refcount; +} + +order_data *odata_load(int id) +{ + return dblib_load_order(id); +} + +int odata_save(order_data *od) +{ + return dblib_save_order(od); +} diff --git a/src/kernel/orderdb.h b/src/kernel/orderdb.h new file mode 100644 index 000000000..800732c5e --- /dev/null +++ b/src/kernel/orderdb.h @@ -0,0 +1,25 @@ +#ifndef H_ORDERDB +#define H_ORDERDB + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + typedef struct order_data { + const char *_str; + int _refcount; + } order_data; + + void odata_create(order_data **pdata, size_t len, const char *str); + void odata_release(order_data * od); + void odata_addref(order_data *od); + + order_data *odata_load(int id); + int odata_save(order_data *od); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/orderdb.test.c b/src/kernel/orderdb.test.c new file mode 100644 index 000000000..bdb6f0a95 --- /dev/null +++ b/src/kernel/orderdb.test.c @@ -0,0 +1,28 @@ +#include +#include + +#include "orderdb.h" + +#include +#include + +#include + +static void test_orderdb(CuTest *tc) { + order_data *od = NULL; + const char * s = "GIB enno 1 Hodor"; + + odata_create(&od, strlen(s) + 1, s); + CuAssertPtrNotNull(tc, od); + CuAssertStrEquals(tc, s, od->_str); + CuAssertTrue(tc, od->_refcount >= 1); + odata_release(od); +} + +CuSuite *get_orderdb_suite(void) +{ + CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_orderdb); + + return suite; +} diff --git a/src/kernel/plane.c b/src/kernel/plane.c index 0dd6793f4..533dab92a 100644 --- a/src/kernel/plane.c +++ b/src/kernel/plane.c @@ -27,6 +27,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* util includes */ #include #include +#include #include #include @@ -234,7 +235,7 @@ plane *create_new_plane(int id, const char *name, int minx, int maxx, int miny, pl->next = NULL; pl->id = id; if (name) - pl->name = strdup(name); + pl->name = str_strdup(name); pl->minx = minx; pl->maxx = maxx; pl->miny = miny; diff --git a/src/kernel/plane.test.c b/src/kernel/plane.test.c index a479a34be..8338cc31f 100644 --- a/src/kernel/plane.test.c +++ b/src/kernel/plane.test.c @@ -9,8 +9,8 @@ static void test_plane(CuTest *tc) { struct region *r; plane *pl; - test_cleanup(); - r = test_create_region(0, 0, 0); + test_setup(); + r = test_create_region(0, 0, NULL); CuAssertPtrEquals(tc, 0, findplane(0, 0)); CuAssertPtrEquals(tc, 0, getplane(r)); CuAssertIntEquals(tc, 0, getplaneid(r)); @@ -38,14 +38,15 @@ static void test_plane(CuTest *tc) { CuAssertIntEquals(tc, 60, plane_center_y(pl)); CuAssertIntEquals(tc, 5, plane_width(pl)); CuAssertIntEquals(tc, 41, plane_height(pl)); + test_teardown(); } static void test_origin(CuTest *tc) { struct faction *f; int x, y; - test_cleanup(); - f = test_create_faction(0); + test_setup(); + f = test_create_faction(NULL); x = 0; y = 0; adjust_coordinates(f, &x, &y, 0); @@ -55,7 +56,7 @@ static void test_origin(CuTest *tc) { adjust_coordinates(f, &x, &y, 0); CuAssertIntEquals(tc, -10, x); CuAssertIntEquals(tc, -20, y); - test_cleanup(); + test_teardown(); } CuSuite *get_plane_suite(void) diff --git a/src/kernel/pool.c b/src/kernel/pool.c index c252be566..e58bc131e 100644 --- a/src/kernel/pool.c +++ b/src/kernel/pool.c @@ -88,9 +88,9 @@ int get_reservation(const unit * u, const item_type * itype) { reservation *res = u->reservations; - if (itype->rtype == get_resourcetype(R_STONE) && (u_race(u)->flags & RCF_STONEGOLEM)) + if (itype->rtype == get_resourcetype(R_STONE) && (u_race(u)->ec_flags & ECF_STONEGOLEM)) return (u->number * GOLEM_STONE); - if (itype->rtype == get_resourcetype(R_IRON) && (u_race(u)->flags & RCF_IRONGOLEM)) + if (itype->rtype == get_resourcetype(R_IRON) && (u_race(u)->ec_flags & ECF_IRONGOLEM)) return (u->number * GOLEM_IRON); while (res && res->type != itype) res = res->next; @@ -114,7 +114,7 @@ int change_reservation(unit * u, const item_type * itype, int value) res->type = itype; res->value = value; } - else if (res && res->value + value <= 0) { + else if (res->value + value <= 0) { *rp = res->next; free(res); return 0; @@ -139,7 +139,7 @@ int set_resvalue(unit * u, const item_type * itype, int value) res->type = itype; res->value = value; } - else if (res && value <= 0) { + else if (value <= 0) { *rp = res->next; free(res); return 0; diff --git a/src/kernel/pool.test.c b/src/kernel/pool.test.c index 4cc44388f..a3de6c021 100644 --- a/src/kernel/pool.test.c +++ b/src/kernel/pool.test.c @@ -19,11 +19,11 @@ void test_reservation(CuTest *tc) { faction *f; region *r; struct resource_type *rtype; - test_cleanup(); + test_setup(); test_create_world(); rtype = rt_get_or_create("money"); it_get_or_create(rtype); - f = test_create_faction(0); + f = test_create_faction(NULL); r = findregion(0, 0); assert(r && f && rtype && rtype->itype); u = test_create_unit(f, r); @@ -39,7 +39,7 @@ void test_reservation(CuTest *tc) { CuAssertIntEquals(tc, 200, get_resource(u, rtype)); CuAssertIntEquals(tc, 200, i_get(u->items, rtype->itype)); - test_cleanup(); + test_teardown(); } void test_pool(CuTest *tc) { @@ -49,16 +49,16 @@ void test_pool(CuTest *tc) { struct resource_type *rtype; ally *al; - test_cleanup(); + test_setup(); test_create_world(); rtype = rt_get_or_create("money"); it_get_or_create(rtype); - f = test_create_faction(0); + f = test_create_faction(NULL); r = findregion(0, 0); assert(r && f && rtype && rtype->itype); u1 = test_create_unit(f, r); u2 = test_create_unit(f, r); - u3 = test_create_unit(test_create_faction(0), r); + u3 = test_create_unit(test_create_faction(NULL), r); assert(u1 && u2); i_change(&u1->items, rtype->itype, 100); set_resvalue(u1, rtype->itype, 50); @@ -85,6 +85,8 @@ void test_pool(CuTest *tc) { CuAssertIntEquals(tc, 100, get_pooled(u1, rtype, GET_ALL, 50)); CuAssertIntEquals(tc, 300, get_pooled(u1, rtype, GET_ALL, 150)); CuAssertIntEquals(tc, 300, get_pooled(u1, rtype, GET_ALL, INT_MAX)); + + test_teardown(); } void test_pool_bug_2042(CuTest *tc) { @@ -93,11 +95,11 @@ void test_pool_bug_2042(CuTest *tc) { region *r; struct resource_type *rtype; - test_cleanup(); + test_setup(); test_create_world(); rtype = rt_get_or_create("money"); it_get_or_create(rtype); - f = test_create_faction(0); + f = test_create_faction(NULL); r = findregion(0, 0); assert(r && f && rtype && rtype->itype); u1 = test_create_unit(f, r); @@ -106,6 +108,8 @@ void test_pool_bug_2042(CuTest *tc) { i_change(&u2->items, rtype->itype, 100); CuAssertIntEquals(tc, 100, get_pooled(u1, rtype, GET_SLACK | GET_POOLED_SLACK, 100)); + + test_teardown(); } void test_pool_use(CuTest *tc) { @@ -115,15 +119,15 @@ void test_pool_use(CuTest *tc) { struct item_type *itype; ally *al; - test_cleanup(); + test_setup(); test_create_world(); itype = it_get_or_create(rt_get_or_create("money")); - f = test_create_faction(0); + f = test_create_faction(NULL); r = findregion(0, 0); assert(r && f && itype); u1 = test_create_unit(f, r); u2 = test_create_unit(f, r); - u3 = test_create_unit(test_create_faction(0), r); + u3 = test_create_unit(test_create_faction(NULL), r); assert(u1 && u2); i_change(&u1->items, itype, 100); set_resvalue(u1, itype, 50); @@ -151,6 +155,8 @@ void test_pool_use(CuTest *tc) { CuAssertIntEquals(tc, 90, get_reservation(u2, itype)); CuAssertIntEquals(tc, 90, use_pooled(u1, itype->rtype, GET_POOLED_RESERVE, 100)); CuAssertIntEquals(tc, 0, i_get(u2->items, itype)); + + test_teardown(); } void test_change_resource(CuTest * tc) @@ -161,12 +167,12 @@ void test_change_resource(CuTest * tc) const char * names[] = { "money", "aura", "permaura", "horse", "hp", 0 }; int i; - test_cleanup(); + test_setup(); test_create_world(); enable_skill(SK_MAGIC, true); r = findregion(0, 0); - f = test_create_faction(0); + f = test_create_faction(NULL); u = test_create_unit(f, r); CuAssertPtrNotNull(tc, u); set_level(u, SK_MAGIC, 5); @@ -178,7 +184,7 @@ void test_change_resource(CuTest * tc) CuAssertIntEquals(tc, have + 1, change_resource(u, rtype, 1)); CuAssertIntEquals(tc, have + 1, get_resource(u, rtype)); } - test_cleanup(); + test_teardown(); } CuSuite *get_pool_suite(void) diff --git a/src/kernel/race.c b/src/kernel/race.c index a73c0e699..cb63647b5 100644 --- a/src/kernel/race.c +++ b/src/kernel/race.c @@ -38,12 +38,12 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* util includes */ #include -#include #include #include #include #include #include +#include #include #include @@ -106,17 +106,18 @@ static void rc_setoption(race *rc, int k, const char *value) { rc->options->key[1] = RCO_NONE; v = rc->options->value; } else { - for (i=0;!v && i < MAXOPTIONS && rc->options->key[i]!=RCO_NONE;++i) { + for (i=0;!v && i < MAXOPTIONS;++i) { if (rc->options->key[i]==key) { v = rc->options->value+i; + break; } - } - if (!v) { - assert(ioptions->value+i; - rc->options->key[i] = key; - if (i+1options->key[i+1]=RCO_NONE; + if (rc->options->key[i]==RCO_NONE) { + v = rc->options->value+i; + rc->options->key[i] = key; + if (i+1 < MAXOPTIONS) { + rc->options->key[i+1]=RCO_NONE; + } + break; } } } @@ -131,7 +132,7 @@ static void rc_setoption(race *rc, int k, const char *value) { v->v = rc_get_or_create(value); } else if (key == RCO_HUNGER) { - v->v = strdup(value); + v->v = str_strdup(value); } else if (key == RCO_TRADEHERB) { v->i = atoi(value); @@ -358,7 +359,7 @@ race *rc_create(const char *zName) log_error("race '%s' has an invalid name. remove spaces\n", zName); assert(strchr(zName, ' ') == NULL); } - rc->_name = strdup(zName); + rc->_name = str_strdup(zName); rc->attack[0].type = AT_COMBATSPELL; for (i = 1; i < RACE_ATTACKS; ++i) @@ -534,21 +535,18 @@ const char *racename(const struct locale *loc, const unit * u, const race * rc) if (prefix != NULL) { static char lbuf[80]; /* FIXME: static return value */ - char *bufp = lbuf; - size_t size = sizeof(lbuf) - 1; - int ch, bytes; - - bytes = (int)strlcpy(bufp, LOC(loc, mkname("prefix", prefix)), size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - - bytes = (int)strlcpy(bufp, LOC(loc, rc_name_s(rc, u->number != 1)), size); - assert(~bufp[0] & 0x80 || !"unicode/not implemented"); - ch = tolower(*(unsigned char *)bufp); - bufp[0] = (char)ch; - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - *bufp = 0; + sbstring sbs; + char ch[2]; + + sbs_init(&sbs, lbuf, sizeof(lbuf)); + sbs_strcpy(&sbs, LOC(loc, mkname("prefix", prefix))); + + str = LOC(loc, rc_name_s(rc, u->number != 1)); + assert(~str[0] & 0x80 || !"unicode/not implemented"); + ch[0] = (char)tolower(*(unsigned char *)str); + ch[1] = 0; + sbs_strcat(&sbs, ch); + sbs_strcat(&sbs, str + 1); return lbuf; } diff --git a/src/kernel/race.h b/src/kernel/race.h index 2990c2158..1203eaed2 100644 --- a/src/kernel/race.h +++ b/src/kernel/race.h @@ -226,11 +226,9 @@ extern "C" { #define RCF_CANSAIL (1<<24) /* Einheit darf Schiffe betreten */ #define RCF_INVISIBLE (1<<25) /* not visible in any report */ #define RCF_SHIPSPEED (1<<26) /* race gets +1 on shipspeed */ -#define RCF_STONEGOLEM (1<<27) /* race gets stonegolem properties */ -#define RCF_IRONGOLEM (1<<28) /* race gets irongolem properties */ +#define RCF_MIGRANTS (1<<27) /* may have migrant units (human bonus) */ +#define RCF_FAMILIAR (1<<28) /* may be a familiar */ #define RCF_ATTACK_MOVED (1<<29) /* may attack if it has moved */ -#define RCF_MIGRANTS (1<<30) /* may have migrant units (human bonus) */ -#define RCF_FAMILIAR (1<<31) /* may be a familiar */ /* Economic flags */ #define ECF_GIVEPERSON (1<<2) /* �bergibt Personen */ @@ -238,6 +236,8 @@ extern "C" { #define ECF_GETITEM (1<<4) /* nimmt Gegenst�nde an */ #define ECF_REC_ETHEREAL (1<<7) /* Rekrutiert aus dem Nichts */ #define ECF_REC_UNLIMITED (1<<8) /* Rekrutiert ohne Limit */ +#define ECF_STONEGOLEM (1<<9) /* race gets stonegolem properties */ +#define ECF_IRONGOLEM (1<<10) /* race gets irongolem properties */ /* Battle-Flags */ #define BF_EQUIPMENT (1<<0) /* Kann Ausr�stung benutzen */ diff --git a/src/kernel/race.test.c b/src/kernel/race.test.c index 2db76a6fd..dcb4ce6f7 100644 --- a/src/kernel/race.test.c +++ b/src/kernel/race.test.c @@ -1,8 +1,12 @@ #include -#include +#include "faction.h" +#include "unit.h" #include "race.h" #include "item.h" +#include +#include + #include #include @@ -18,7 +22,7 @@ static void test_rc_name(CuTest *tc) { CuAssertStrEquals(tc, "race::human_p", rc_name_s(rc, NAME_PLURAL)); CuAssertStrEquals(tc, "race::human_d", rc_name_s(rc, NAME_DEFINITIVE)); CuAssertStrEquals(tc, "race::human_x", rc_name_s(rc, NAME_CATEGORY)); - test_cleanup(); + test_teardown(); } static void test_rc_defaults(CuTest *tc) { @@ -44,7 +48,7 @@ static void test_rc_defaults(CuTest *tc) { CuAssertIntEquals(tc, 0, rc->df_bonus); CuAssertIntEquals(tc, 0, rc->battle_flags); CuAssertIntEquals(tc, PERSON_WEIGHT, rc->weight); - test_cleanup(); + test_teardown(); } static void test_rc_find(CuTest *tc) { @@ -52,7 +56,7 @@ static void test_rc_find(CuTest *tc) { test_setup(); rc = test_create_race("hungryhippos"); CuAssertPtrEquals(tc, rc, (void *)rc_find("hungryhippos")); - test_cleanup(); + test_teardown(); } static void test_race_get(CuTest *tc) { @@ -68,7 +72,7 @@ static void test_race_get(CuTest *tc) { CuAssertPtrEquals(tc, (void *)rc, (void *)rc_find("elf")); free_races(); CuAssertTrue(tc, rc_changed(&cache)); - test_cleanup(); + test_teardown(); } static void test_old_race(CuTest *tc) @@ -83,7 +87,7 @@ static void test_old_race(CuTest *tc) rc2 = test_create_race("human"); CuAssertIntEquals(tc, RC_ELF, old_race(rc1)); CuAssertIntEquals(tc, RC_HUMAN, old_race(rc2)); - test_cleanup(); + test_teardown(); } static void test_rc_set_param(CuTest *tc) { @@ -100,7 +104,7 @@ static void test_rc_set_param(CuTest *tc) { CuAssertIntEquals(tc, 400, rc_scare(rc)); rc_set_param(rc, "hunger.damage", "1d10+12"); CuAssertStrEquals(tc, "1d10+12", rc_hungerdamage(rc)); - test_cleanup(); + test_teardown(); } static void test_rc_can_use(CuTest *tc) { @@ -148,7 +152,24 @@ static void test_rc_can_use(CuTest *tc) { rc->mask_item = 0; CuAssertTrue(tc, ! rc_can_use(rc, itype)); - test_cleanup(); + test_teardown(); +} + +static void test_racename(CuTest *tc) { + unit *u; + struct locale * lang; + test_setup(); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); + u->faction->locale = lang = test_create_locale(); + locale_setstring(lang, "race::human_p", "Menschen"); + locale_setstring(lang, "race::human", "Mensch"); + locale_setstring(lang, "prefix::dark", "Dunkel"); + CuAssertStrEquals(tc, "Mensch", racename(lang, u, u->_race)); + u->number = 2; + CuAssertStrEquals(tc, "Menschen", racename(lang, u, u->_race)); + set_prefix(&u->faction->attribs, "dark"); + CuAssertStrEquals(tc, "Dunkelmenschen", racename(lang, u, u->_race)); + test_teardown(); } CuSuite *get_race_suite(void) @@ -161,6 +182,7 @@ CuSuite *get_race_suite(void) SUITE_ADD_TEST(suite, test_rc_find); SUITE_ADD_TEST(suite, test_rc_set_param); SUITE_ADD_TEST(suite, test_rc_can_use); + SUITE_ADD_TEST(suite, test_racename); return suite; } diff --git a/src/kernel/region.c b/src/kernel/region.c index c7e3841fb..3f25f156b 100644 --- a/src/kernel/region.c +++ b/src/kernel/region.c @@ -42,7 +42,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* util includes */ #include #include -#include #include #include #include @@ -52,6 +51,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include #include @@ -117,14 +117,14 @@ const char *write_regionname(const region * r, const faction * f, char *buffer, char *buf = (char *)buffer; const struct locale *lang = f ? f->locale : 0; if (r == NULL) { - strlcpy(buf, "(null)", size); + str_strlcpy(buf, "(null)", size); } else { plane *pl = rplane(r); int nx = r->x, ny = r->y; pnormalize(&nx, &ny, pl); adjust_coordinates(f, &nx, &ny, pl); - slprintf(buf, size, "%s (%d,%d)", rname(r, lang), nx, ny); + snprintf(buf, size, "%s (%d,%d)", rname(r, lang), nx, ny); } return buffer; } @@ -139,7 +139,7 @@ const char *regionname(const region * r, const faction * f) int region_maxworkers(const region *r) { - int size = production(r); + int size = max_production(r); int treespace = (rtrees(r, 2) + rtrees(r, 1) / 2) * TREESIZE; return MAX(size - treespace, MIN(size / 10, 200)); } @@ -664,7 +664,7 @@ void rsetherbs(region *r, int value) assert(r->land || value==0); assert(value >= 0 && value<=SHRT_MAX); if (r->land) { - r->land->herbs = (short)value; + r->land->herbs = value; } } @@ -711,7 +711,7 @@ const item_type *r_luxury(const region * r) { struct demand *dmd; if (r->land) { - assert(r->land->demands || !"need to call fix_demands on a region"); + assert(r->land->demands || !"need to call fix_demand on a region"); for (dmd = r->land->demands; dmd; dmd = dmd->next) { if (dmd->value == 0) return dmd->type->itype; @@ -1060,7 +1060,6 @@ void terraform_region(region * r, const terrain_type * terrain) rawmaterial **lrm = &r->resources; assert(terrain); - while (*lrm) { rawmaterial *rm = *lrm; const resource_type *rtype = NULL; @@ -1191,7 +1190,7 @@ void terraform_region(region * r, const terrain_type * terrain) } if (itype != NULL) { rsetherbtype(r, itype); - rsetherbs(r, (short)(50 + rng_int() % 31)); + rsetherbs(r, 50 + rng_int() % 31); } else { rsetherbtype(r, NULL); @@ -1244,7 +1243,7 @@ void terraform_region(region * r, const terrain_type * terrain) * egal ob durch den spell oder anderes angelegt. **/ #include "curse.h" -int production(const region * r) +int max_production(const region * r) { /* muß rterrain(r) sein, nicht rterrain() wegen rekursion */ int p = r->terrain->size; @@ -1420,7 +1419,7 @@ void region_setinfo(struct region *r, const char *info) { assert(r->land); free(r->land->display); - r->land->display = (info && info[0]) ? strdup(info) : 0; + r->land->display = (info && info[0]) ? str_strdup(info) : 0; } const char *region_getinfo(const region * r) @@ -1432,7 +1431,7 @@ void region_setname(struct region *r, const char *name) { if (r->land) { free(r->land->name); - r->land->name = name ? strdup(name) : 0; + r->land->name = name ? str_strdup(name) : 0; } } @@ -1456,7 +1455,7 @@ int region_get_morale(const region * r) void region_set_morale(region * r, int morale, int turn) { if (r->land) { - r->land->morale = (short)morale; + r->land->morale = morale; if (turn >= 0 && r->land->ownership) { r->land->ownership->morale_turn = turn; } diff --git a/src/kernel/region.h b/src/kernel/region.h index 7f86f397f..ce1f9ea94 100644 --- a/src/kernel/region.h +++ b/src/kernel/region.h @@ -102,8 +102,8 @@ extern "C" { char *display; demand *demands; const struct item_type *herbtype; - short herbs; - short morale; + int herbs; + int morale; int trees[3]; /* 0 -> seeds, 1 -> shoots, 2 -> trees */ int horses; int peasants; @@ -240,7 +240,7 @@ extern "C" { extern const int delta_x[MAXDIRECTIONS]; extern const int delta_y[MAXDIRECTIONS]; direction_t dir_invert(direction_t dir); - int production(const struct region *r); + int max_production(const struct region *r); void region_set_owner(struct region *r, struct faction *owner, int turn); struct faction *region_get_owner(const struct region *r); diff --git a/src/kernel/region.test.c b/src/kernel/region.test.c index 8f16842c4..4baa807c8 100644 --- a/src/kernel/region.test.c +++ b/src/kernel/region.test.c @@ -31,7 +31,7 @@ void test_terraform(CuTest *tc) { CuAssertIntEquals(tc, 0, r->land->demands->type->price); terraform_region(r, t_ocean); CuAssertPtrEquals(tc, 0, r->land); - test_cleanup(); + test_teardown(); } static void test_region_get_owner(CuTest *tc) { @@ -40,17 +40,17 @@ static void test_region_get_owner(CuTest *tc) { unit *u1, *u2; test_setup(); - r = test_create_region(0, 0, 0); + r = test_create_region(0, 0, NULL); b1 = test_create_building(r, NULL); b2 = test_create_building(r, NULL); b1->size = 5; b2->size = 10; - u1 = test_create_unit(test_create_faction(0), r); + u1 = test_create_unit(test_create_faction(NULL), r); u_set_building(u1, b1); - u2 = test_create_unit(test_create_faction(0), r); + u2 = test_create_unit(test_create_faction(NULL), r); u_set_building(u2, b2); CuAssertPtrEquals(tc, u2->faction, region_get_owner(r)); - test_cleanup(); + test_teardown(); } static void test_region_getset_resource(CuTest *tc) { @@ -75,7 +75,7 @@ static void test_region_getset_resource(CuTest *tc) { CuAssertIntEquals(tc, 10, region_getresource(r, get_resourcetype(R_PEASANT))); CuAssertIntEquals(tc, 10, rpeasants(r)); - test_cleanup(); + test_teardown(); } static void test_trees(CuTest *tc) { @@ -93,7 +93,7 @@ static void test_trees(CuTest *tc) { CuAssertIntEquals(tc, MAXTREES, rtrees(r, 0)); rsettrees(r, 0, MAXTREES+100); CuAssertIntEquals(tc, MAXTREES, rtrees(r, 0)); - test_cleanup(); + test_teardown(); } CuSuite *get_region_suite(void) diff --git a/src/kernel/render.h b/src/kernel/render.h index 688c07f2b..f12d55b9b 100644 --- a/src/kernel/render.h +++ b/src/kernel/render.h @@ -24,5 +24,5 @@ struct message; /* TODO: this could be nicer and faster * call with MSG(("msg_name", "param", p), buf, faction). */ -#define MSG(makemsg, buf, size, loc, ud) { struct message * m = msg_message makemsg; nr_render(m, loc, buf, size, ud); msg_release(m); } -#define RENDER(f, buf, size, mcreate) { struct message * m = msg_message mcreate; nr_render(m, f->locale, buf, size, f); msg_release(m); } +#define MSG(makemsg, buf, size, loc, ud) { struct message * mm = msg_message makemsg; nr_render(mm, loc, buf, size, ud); msg_release(mm); } +#define RENDER(f, buf, size, mcreate) { struct message * mr = msg_message mcreate; nr_render(mr, f->locale, buf, size, f); msg_release(mr); } diff --git a/src/kernel/resources.c b/src/kernel/resources.c index 842cb83ba..bcf26efb3 100644 --- a/src/kernel/resources.c +++ b/src/kernel/resources.c @@ -21,6 +21,7 @@ #include "region.h" #include "terrain.h" +#include #include #include @@ -124,30 +125,6 @@ static void terraform_default(struct rawmaterial *res, const region * r) UNUSED_ARG(r); } -#ifdef RANDOM_CHANGE -static void resource_random_change(int *pvalue, bool used) -{ - int split = 5; - int rnd = rng_int() % 100; - - if (pvalue == 0 || rnd % 10 >= 10) - return; - if (used) - split = 4; - /* if a resource was mined this round, there is a 6% probability - * of a decline and a 4% probability of a raise. */ - /* if it wasn't mined this round, there is an equal probability - * of 5% for a decline or a raise. */ - if (rnd < split) { - (*pvalue)++; - } else { - (*pvalue)--; - } - if ((*pvalue) < 0) - (*pvalue) = 0; -} -#endif - static int visible_default(const rawmaterial * res, int skilllevel) /* resources are visible, if skill equals minimum skill to mine them * plus current level of difficulty */ diff --git a/src/kernel/save.c b/src/kernel/save.c index 227304339..a4bfdcbca 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -59,7 +59,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include -#include #include #include #include @@ -70,15 +69,18 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include #include #include #include +#include #include #include #include #include #include +#include #include #include @@ -102,71 +104,6 @@ int firstx = 0, firsty = 0; /* TODO: is this still important? */ int enc_gamedata = ENCODING_UTF8; -/* local symbols */ -static region *current_region; - -char *rns(FILE * f, char *c, size_t size) -{ - char *s = c; - do { - *s = (char)getc(f); - } while (*s != '"'); - - for (;;) { - *s = (char)getc(f); - if (*s == '"') - break; - if (s < c + size) - ++s; - } - *s = 0; - return c; -} - -/* ------------------------------------------------------------- */ - -/* #define INNER_WORLD */ -/* fürs debuggen nur den inneren Teil der Welt laden */ -/* -9;-27;-1;-19;Sumpfloch */ -int inner_world(region * r) -{ - static int xy[2] = { 18, -45 }; - static int size[2] = { 27, 27 }; - - if (r->x >= xy[0] && r->x < xy[0] + size[0] && r->y >= xy[1] - && r->y < xy[1] + size[1]) - return 2; - if (r->x >= xy[0] - 9 && r->x < xy[0] + size[0] + 9 && r->y >= xy[1] - 9 - && r->y < xy[1] + size[1] + 9) - return 1; - return 0; -} - -int maxregions = -1; -int loadplane = 0; - -enum { - U_MAN, - U_UNDEAD, - U_ILLUSION, - U_FIREDRAGON, - U_DRAGON, - U_WYRM, - U_SPELL, - U_TAVERNE, - U_MONSTER, - U_BIRTHDAYDRAGON, - U_TREEMAN, - MAXTYPES -}; - -race_t typus2race(unsigned char typus) -{ - if (typus > 0 && typus <= 11) - return (race_t)(typus - 1); - return NORACE; -} - static void read_alliances(gamedata *data) { storage *store = data->store; @@ -222,7 +159,7 @@ void read_planes(gamedata *data) { } pl->id = id; READ_STR(store, name, sizeof(name)); - pl->name = strdup(name); + pl->name = str_strdup(name); READ_INT(store, &pl->minx); READ_INT(store, &pl->maxx); READ_INT(store, &pl->miny); @@ -356,17 +293,17 @@ static void write_owner(gamedata *data, region_owner * owner) int current_turn(void) { - char zText[MAX_PATH]; + char zText[PATH_MAX]; int cturn = 0; FILE *F; - join_path(basepath(), "turn", zText, sizeof(zText)); + path_join(basepath(), "turn", zText, sizeof(zText)); F = fopen(zText, "r"); if (!F) { perror(zText); } else { - int c = fscanf(F, "%d\n", &cturn); + int c = fscanf(F, "%4d\n", &cturn); fclose(F); if (c != 1) { return -1; @@ -379,28 +316,53 @@ static void writeorder(gamedata *data, const struct order *ord, const struct locale *lang) { char obuf[1024]; - write_order(ord, obuf, sizeof(obuf)); + write_order(ord, lang, obuf, sizeof(obuf)); if (obuf[0]) WRITE_STR(data->store, obuf); } +static void read_skill(gamedata *data, skill *sv) { + int val; + READ_INT(data->store, &val); + assert(val < MAXSKILLS); + sv->id = (skill_t)val; + if (sv->id != NOSKILL) { + READ_INT(data->store, &val); + assert(val < CHAR_MAX); + sv->old = sv->level = val; + READ_INT(data->store, &val); + assert(val < CHAR_MAX); + sv->weeks = val; + } +} + +static int skill_cmp(const void *a, const void *b) { + const skill * sa = (const skill *)a; + const skill * sb = (const skill *)b; + return sa->id - sb->id; +} + static void read_skills(gamedata *data, unit *u) { if (data->version < SKILLSORT_VERSION) { + skill skills[MAXSKILLS], *sv = skills; + + u->skill_size = 0; for (;;) { - int n = NOSKILL, level, weeks; - skill_t sk; - READ_INT(data->store, &n); - sk = (skill_t)n; - if (sk == NOSKILL) break; - READ_INT(data->store, &level); - READ_INT(data->store, &weeks); - if (level) { - skill *sv = add_skill(u, sk); - sv->level = sv->old = (unsigned char)level; - sv->weeks = (unsigned char)weeks; + read_skill(data, sv); + if (sv->id == NOSKILL) break; + if (sv->level > 0) { + ++sv; + ++u->skill_size; } } + if (u->skill_size > 0) { + size_t sz = u->skill_size * sizeof(skill); + + qsort(skills, u->skill_size, sizeof(skill), skill_cmp); + u->skills = malloc(sz); + memcpy(u->skills, skills, sz); + } } else { int i; @@ -408,12 +370,7 @@ static void read_skills(gamedata *data, unit *u) u->skills = malloc(sizeof(skill)*u->skill_size); for (i = 0; i != u->skill_size; ++i) { skill *sv = u->skills + i; - int val; - READ_INT(data->store, &val); - sv->id = (skill_t)val; - READ_INT(data->store, &sv->level); - sv->old = sv->level; - READ_INT(data->store, &sv->weeks); + read_skill(data, sv); } } } @@ -486,17 +443,12 @@ unit *read_unit(gamedata *data) if (unicode_utf8_trim(obuf)!=0) { log_warning("trim unit %s name to '%s'", itoa36(u->no), obuf); } - u->_name = obuf[0] ? strdup(obuf) : 0; - if (lomem) { - READ_STR(data->store, NULL, 0); - } - else { - READ_STR(data->store, obuf, sizeof(obuf)); - if (unicode_utf8_trim(obuf)!=0) { - log_warning("trim unit %s info to '%s'", itoa36(u->no), obuf); - } - u->display = obuf[0] ? strdup(obuf) : 0; + u->_name = obuf[0] ? str_strdup(obuf) : 0; + READ_STR(data->store, obuf, sizeof(obuf)); + if (unicode_utf8_trim(obuf)!=0) { + log_warning("trim unit %s info to '%s'", itoa36(u->no), obuf); } + u->display = obuf[0] ? str_strdup(obuf) : 0; READ_INT(data->store, &number); set_number(u, number); @@ -557,24 +509,23 @@ unit *read_unit(gamedata *data) p = n = 0; orderp = &u->orders; while (obuf[0]) { - if (!lomem) { - order *ord = parse_order(obuf, u->faction->locale); - if (ord != NULL) { - if (++n < MAXORDERS) { - if (!is_persistent(ord) || ++p < MAXPERSISTENT) { - *orderp = ord; - orderp = &ord->next; - ord = NULL; - } - else if (p == MAXPERSISTENT) { - log_info("%s had %d or more persistent orders", unitname(u), MAXPERSISTENT); - } + order *ord = parse_order(obuf, u->faction->locale); + if (ord != NULL) { + if (++n < MAXORDERS) { + if (!is_persistent(ord) || ++p < MAXPERSISTENT) { + *orderp = ord; + orderp = &ord->next; + ord = NULL; } - else if (n == MAXORDERS) { - log_info("%s had %d or more orders", unitname(u), MAXORDERS); + else if (p == MAXPERSISTENT) { + log_info("%s had %d or more persistent orders", unitname(u), MAXPERSISTENT); } - if (ord != NULL) - free_order(ord); + } + else if (n == MAXORDERS) { + log_info("%s had %d or more orders", unitname(u), MAXORDERS); + } + if (ord != NULL) { + free_order(ord); } } READ_STR(data->store, obuf, sizeof(obuf)); @@ -659,14 +610,9 @@ void write_unit(gamedata *data, const unit * u) } static void read_regioninfo(gamedata *data, const region *r, char *info, size_t len) { - if (lomem) { - READ_STR(data->store, NULL, 0); - } - else { - READ_STR(data->store, info, len); - if (unicode_utf8_trim(info) != 0) { - log_warning("trim region %d info to '%s'", r->uid, info); - } + READ_STR(data->store, info, len); + if (unicode_utf8_trim(info) != 0) { + log_warning("trim region %d info to '%s'", r->uid, info); } } @@ -687,7 +633,6 @@ static region *readregion(gamedata *data, int x, int y) } else { assert(uid == 0 || r->uid == uid); - current_region = r; while (r->attribs) a_remove(&r->attribs, r->attribs); if (r->land) { @@ -725,7 +670,7 @@ static region *readregion(gamedata *data, int x, int y) if (unicode_utf8_trim(name) != 0) { log_warning("trim region %d name to '%s'", uid, name); }; - r->land->name = strdup(name); + r->land->name = str_strdup(name); } if (r->land) { int i; @@ -965,7 +910,7 @@ static char * getpasswd(int fno) { assert(line[slen] == '\n'); line[slen] = 0; fclose(F); - return strdup(line + len + 1); + return str_strdup(line + len + 1); } } fclose(F); @@ -1057,19 +1002,21 @@ faction *read_faction(gamedata * data) if (unicode_utf8_trim(name)!=0) { log_warning("trim faction %s name to '%s'", itoa36(f->no), name); }; - f->name = strdup(name); + f->name = str_strdup(name); READ_STR(data->store, name, sizeof(name)); if (unicode_utf8_trim(name)!=0) { log_warning("trim faction %s banner to '%s'", itoa36(f->no), name); }; - f->banner = strdup(name); + f->banner = str_strdup(name); log_debug(" - Lese Partei %s (%s)", f->name, itoa36(f->no)); READ_STR(data->store, name, sizeof(name)); - if (set_email(&f->email, name) != 0) { - log_warning("Invalid email address for faction %s: %s", itoa36(f->no), name); - set_email(&f->email, ""); + if (check_email(name) == 0) { + faction_setemail(f, name); + } else { + log_warning("Invalid email address for faction %s: %s", itoa36(f->no), name); + faction_setemail(f, NULL); } read_password(data, f); @@ -1124,14 +1071,14 @@ faction *read_faction(gamedata * data) READ_INT(data->store, &n); f->options = n; - n = want(O_REPORT) | want(O_COMPUTER); + n = WANT_OPTION(O_REPORT) | WANT_OPTION(O_COMPUTER); if ((f->options & n) == 0) { /* Kein Report eingestellt, Fehler */ f->options |= n; } if (data->version < JSON_REPORT_VERSION) { /* mistakes were made in the past*/ - f->options &= ~want(O_JSON); + f->options &= ~WANT_OPTION(O_JSON); } read_allies(data, f); read_groups(data, f); @@ -1169,7 +1116,7 @@ void write_faction(gamedata *data, const faction * f) WRITE_STR(data->store, f->name); WRITE_STR(data->store, f->banner); - WRITE_STR(data->store, f->email); + WRITE_STR(data->store, f->email?f->email:""); write_password(data, f); WRITE_TOK(data->store, locale_name(f->locale)); WRITE_INT(data->store, f->lastorders); @@ -1192,7 +1139,7 @@ void write_faction(gamedata *data, const faction * f) WRITE_INT(data->store, ur->y); } WRITE_SECTION(data->store); - WRITE_INT(data->store, f->options & ~want(O_DEBUG)); + WRITE_INT(data->store, f->options & ~WANT_OPTION(O_DEBUG)); WRITE_SECTION(data->store); for (sf = f->allies; sf; sf = sf->next) { @@ -1226,7 +1173,7 @@ static int cb_sb_maxlevel(spellbook_entry *sbe, void *cbdata) { int readgame(const char *filename) { int n, stream_version; - char path[MAX_PATH]; + char path[PATH_MAX]; gamedata gdata = { 0 }; storage store; stream strm; @@ -1234,7 +1181,7 @@ int readgame(const char *filename) size_t sz; log_debug("- reading game data from %s", filename); - join_path(datapath(), filename, path, sizeof(path)); + path_join(datapath(), filename, path, sizeof(path)); F = fopen(path, "rb"); if (!F) { @@ -1286,17 +1233,12 @@ struct building *read_building(gamedata *data) { if (unicode_utf8_trim(name)!=0) { log_warning("trim building %s name to '%s'", itoa36(b->no), name); } - b->name = strdup(name); - if (lomem) { - READ_STR(store, NULL, 0); - } - else { - READ_STR(store, name, sizeof(name)); - if (unicode_utf8_trim(name)!=0) { - log_warning("trim building %s info to '%s'", itoa36(b->no), name); - } - b->display = strdup(name); + b->name = str_strdup(name); + READ_STR(store, name, sizeof(name)); + if (unicode_utf8_trim(name)!=0) { + log_warning("trim building %s info to '%s'", itoa36(b->no), name); } + b->display = str_strdup(name); READ_INT(store, &b->size); READ_STR(store, name, sizeof(name)); b->type = bt_find(name); @@ -1345,17 +1287,12 @@ ship *read_ship(gamedata *data) if (unicode_utf8_trim(name)!=0) { log_warning("trim ship %s name to '%s'", itoa36(sh->no), name); } - sh->name = strdup(name); - if (lomem) { - READ_STR(store, NULL, 0); - } - else { - READ_STR(store, name, sizeof(name)); - if (unicode_utf8_trim(name)!=0) { - log_warning("trim ship %s info to '%s'", itoa36(sh->no), name); - } - sh->display = strdup(name); + sh->name = str_strdup(name); + READ_STR(store, name, sizeof(name)); + if (unicode_utf8_trim(name)!=0) { + log_warning("trim ship %s info to '%s'", itoa36(sh->no), name); } + sh->display = str_strdup(name); READ_STR(store, name, sizeof(name)); sh->type = st_find(name); if (sh->type == NULL) { @@ -1460,7 +1397,6 @@ int read_game(gamedata *data) building **bp; ship **shp; unit *u; - int rmax = maxregions; storage * store = data->store; const struct building_type *bt_lighthouse = bt_find("lighthouse"); const struct race *rc_spell = rc_find("spell"); @@ -1504,11 +1440,9 @@ int read_game(gamedata *data) /* Regionen */ READ_INT(store, &nread); - assert(nread < MAXREGIONS && nread>=0); - if (rmax < 0) { - rmax = nread; - } - log_debug(" - Einzulesende Regionen: %d/%d", rmax, nread); + assert(nread < MAXREGIONS && nread >=0); + + log_debug(" - Einzulesende Regionen: %d", nread); while (--nread >= 0) { unit **up; @@ -1518,7 +1452,7 @@ int read_game(gamedata *data) /* Burgen */ READ_INT(store, &p); if (p > 0 && !r->land) { - log_error("%s, uid=%d has %d buildings", regionname(r, NULL), r->uid, p); + log_debug("%s, uid=%d has %d %s", regionname(r, NULL), r->uid, p, (p==1) ? "building" : "buildings"); } bp = &r->buildings; @@ -1571,7 +1505,6 @@ int read_game(gamedata *data) update_interval(u->faction, r); } } - --rmax; } read_borders(data); @@ -1633,9 +1566,6 @@ int read_game(gamedata *data) fix_familiars(); } - if (loadplane || maxregions >= 0) { - remove_empty_factions(); - } log_debug("Done loading turn %d.", turn); return 0; @@ -1654,22 +1584,20 @@ static void clear_npc_orders(faction *f) int writegame(const char *filename) { int n; - char path[MAX_PATH]; + char path[PATH_MAX]; gamedata gdata; storage store; stream strm; FILE *F; create_directories(); - join_path(datapath(), filename, path, sizeof(path)); -#ifdef HAVE_UNISTD_H + path_join(datapath(), filename, path, sizeof(path)); /* make sure we don't overwrite an existing file (hard links) */ - if (remove(path)!=0) { - if (errno==ENOENT) { + if (remove(path) != 0) { + if (errno == ENOENT) { errno = 0; } } -#endif F = fopen(path, "wb"); if (!F) { perror(path); diff --git a/src/kernel/save.test.c b/src/kernel/save.test.c index 82cd8662c..4e6e0e2d4 100644 --- a/src/kernel/save.test.c +++ b/src/kernel/save.test.c @@ -1,8 +1,6 @@ #include #include #include -#include -#include #include #include "save.h" @@ -20,11 +18,16 @@ #include #include #include -#include #include +#include +#include #include +#include +#include #include + +#include #include #include #include @@ -36,13 +39,13 @@ static void test_readwrite_data(CuTest * tc) { const char *filename = "test.dat"; - char path[MAX_PATH]; + char path[PATH_MAX]; test_setup(); CuAssertIntEquals(tc, 0, writegame(filename)); CuAssertIntEquals(tc, 0, readgame(filename)); - join_path(datapath(), filename, path, sizeof(path)); + path_join(datapath(), filename, path, sizeof(path)); CuAssertIntEquals(tc, 0, remove(path)); - test_cleanup(); + test_teardown(); } static void test_readwrite_unit(CuTest * tc) @@ -56,8 +59,8 @@ static void test_readwrite_unit(CuTest * tc) int fno; test_setup(); - r = test_create_region(0, 0, 0); - f = test_create_faction(0); + r = test_create_region(0, 0, NULL); + f = test_create_faction(NULL); fno = f->no; u = test_create_unit(f, r); unit_setname(u, " Hodor "); @@ -74,8 +77,8 @@ static void test_readwrite_unit(CuTest * tc) data.strm.api->rewind(data.strm.handle); free_gamedata(); - f = test_create_faction(0); - r = test_create_region(0, 0, 0); + f = test_create_faction(NULL); + r = test_create_region(0, 0, NULL); renumber_faction(f, fno); gamedata_init(&data, &store, RELEASE_VERSION); u = read_unit(&data); @@ -88,7 +91,7 @@ static void test_readwrite_unit(CuTest * tc) mstream_done(&data.strm); gamedata_done(&data); move_unit(u, r, NULL); /* this makes sure that u doesn't leak */ - test_cleanup(); + test_teardown(); } static void test_readwrite_faction(CuTest * tc) @@ -98,9 +101,9 @@ static void test_readwrite_faction(CuTest * tc) faction *f; test_setup(); - f = test_create_faction(0); + f = test_create_faction(NULL); free(f->name); - f->name = strdup(" Hodor "); + f->name = str_strdup(" Hodor "); CuAssertStrEquals(tc, " Hodor ", f->name); mstream_init(&data.strm); gamedata_init(&data, &store, RELEASE_VERSION); @@ -117,7 +120,7 @@ static void test_readwrite_faction(CuTest * tc) mstream_done(&data.strm); gamedata_done(&data); - test_cleanup(); + test_teardown(); } static void test_readwrite_region(CuTest * tc) @@ -128,9 +131,9 @@ static void test_readwrite_region(CuTest * tc) const char * lipsum = "Lorem ipsum dolor sit amet"; test_setup(); - r = test_create_region(0, 0, 0); + r = test_create_region(0, 0, NULL); free(r->land->name); - r->land->name = strdup(" Hodor "); + r->land->name = str_strdup(" Hodor "); CuAssertStrEquals(tc, " Hodor ", r->land->name); region_setinfo(r, lipsum); CuAssertStrEquals(tc, lipsum, r->land->display); @@ -149,7 +152,7 @@ static void test_readwrite_region(CuTest * tc) mstream_done(&data.strm); gamedata_done(&data); - test_cleanup(); + test_teardown(); } static void test_readwrite_building(CuTest * tc) @@ -160,10 +163,10 @@ static void test_readwrite_building(CuTest * tc) region *r; test_setup(); - r = test_create_region(0, 0, 0); - b = test_create_building(r, 0); + r = test_create_region(0, 0, NULL); + b = test_create_building(r, NULL); free(b->name); - b->name = strdup(" Hodor "); + b->name = str_strdup(" Hodor "); CuAssertStrEquals(tc, " Hodor ", b->name); mstream_init(&data.strm); gamedata_init(&data, &store, RELEASE_VERSION); @@ -171,7 +174,7 @@ static void test_readwrite_building(CuTest * tc) data.strm.api->rewind(data.strm.handle); free_gamedata(); - r = test_create_region(0, 0, 0); + r = test_create_region(0, 0, NULL); gamedata_init(&data, &store, RELEASE_VERSION); b = read_building(&data); CuAssertPtrNotNull(tc, b); @@ -182,7 +185,7 @@ static void test_readwrite_building(CuTest * tc) mstream_done(&data.strm); gamedata_done(&data); - test_cleanup(); + test_teardown(); } static void test_readwrite_ship(CuTest * tc) @@ -193,10 +196,10 @@ static void test_readwrite_ship(CuTest * tc) region *r; test_setup(); - r = test_create_region(0, 0, 0); - sh = test_create_ship(r, 0); + r = test_create_region(0, 0, NULL); + sh = test_create_ship(r, NULL); free(sh->name); - sh->name = strdup(" Hodor "); + sh->name = str_strdup(" Hodor "); CuAssertStrEquals(tc, " Hodor ", sh->name); mstream_init(&data.strm); gamedata_init(&data, &store, RELEASE_VERSION); @@ -204,7 +207,7 @@ static void test_readwrite_ship(CuTest * tc) data.strm.api->rewind(data.strm.handle); free_gamedata(); - r = test_create_region(0, 0, 0); + r = test_create_region(0, 0, NULL); gamedata_init(&data, &store, RELEASE_VERSION); sh = read_ship(&data); CuAssertPtrNotNull(tc, sh); @@ -215,7 +218,7 @@ static void test_readwrite_ship(CuTest * tc) mstream_done(&data.strm); gamedata_done(&data); - test_cleanup(); + test_teardown(); } static void test_readwrite_attrib(CuTest *tc) { @@ -240,7 +243,7 @@ static void test_readwrite_attrib(CuTest *tc) { CuAssertIntEquals(tc, 43, key_get(a, 42)); a_removeall(&a, NULL); - test_cleanup(); + test_teardown(); } static void test_readwrite_dead_faction_group(CuTest *tc) { @@ -255,14 +258,14 @@ static void test_readwrite_dead_faction_group(CuTest *tc) { mstream_init(&data.strm); gamedata_init(&data, &store, RELEASE_VERSION); - test_cleanup(); - f = test_create_faction(0); + test_setup(); + f = test_create_faction(NULL); fno = f->no; CuAssertPtrEquals(tc, f, factions); CuAssertPtrEquals(tc, 0, f->next); - f2 = test_create_faction(0); + f2 = test_create_faction(NULL); CuAssertPtrEquals(tc, f2, factions->next); - u = test_create_unit(f2, test_create_region(0, 0, 0)); + u = test_create_unit(f2, test_create_region(0, 0, NULL)); CuAssertPtrNotNull(tc, u); g = join_group(u, "group"); CuAssertPtrNotNull(tc, g); @@ -288,7 +291,7 @@ static void test_readwrite_dead_faction_group(CuTest *tc) { CuAssertPtrEquals(tc, 0, g->allies); mstream_done(&data.strm); gamedata_done(&data); - test_cleanup(); + test_teardown(); } static void test_readwrite_dead_faction_regionowner(CuTest *tc) { @@ -302,8 +305,8 @@ static void test_readwrite_dead_faction_regionowner(CuTest *tc) { gamedata_init(&data, &store, RELEASE_VERSION); config_set("rules.region_owners", "1"); - f = test_create_faction(0); - test_create_unit(f, r = test_create_region(0, 0, 0)); + f = test_create_faction(NULL); + test_create_unit(f, r = test_create_region(0, 0, NULL)); region_set_owner(r, f, 0); destroyfaction(&factions); CuAssertTrue(tc, !f->_alive); @@ -320,7 +323,7 @@ static void test_readwrite_dead_faction_regionowner(CuTest *tc) { r = regions; CuAssertPtrNotNull(tc, r); CuAssertPtrEquals(tc, 0, region_get_owner(r)); - test_cleanup(); + test_teardown(); } static void test_readwrite_dead_faction_changefaction(CuTest *tc) { @@ -331,10 +334,10 @@ static void test_readwrite_dead_faction_changefaction(CuTest *tc) { trigger *tr; unit * u; - test_cleanup(); - f = test_create_faction(0); - f2 = test_create_faction(0); - u = test_create_unit(f2, r = test_create_region(0, 0, 0)); + test_setup(); + f = test_create_faction(NULL); + f2 = test_create_faction(NULL); + u = test_create_unit(f2, r = test_create_region(0, 0, NULL)); tr = trigger_changefaction(u, f); add_trigger(&u->attribs, "timer", trigger_timeout(10, tr)); CuAssertPtrNotNull(tc, a_find(u->attribs, &at_eventhandler)); @@ -357,7 +360,7 @@ static void test_readwrite_dead_faction_changefaction(CuTest *tc) { u = r->units; CuAssertPtrNotNull(tc, u); CuAssertPtrEquals(tc, 0, a_find(u->attribs, &at_eventhandler)); - test_cleanup(); + test_teardown(); } static void test_readwrite_dead_faction_createunit(CuTest *tc) { @@ -368,10 +371,10 @@ static void test_readwrite_dead_faction_createunit(CuTest *tc) { trigger *tr; unit * u; - test_cleanup(); - f = test_create_faction(0); - f2 = test_create_faction(0); - u = test_create_unit(f2, r = test_create_region(0, 0, 0)); + test_setup(); + f = test_create_faction(NULL); + f2 = test_create_faction(NULL); + u = test_create_unit(f2, r = test_create_region(0, 0, NULL)); tr = trigger_createunit(r, f, f->race, 1); add_trigger(&u->attribs, "timer", trigger_timeout(10, tr)); CuAssertPtrNotNull(tc, a_find(u->attribs, &at_eventhandler)); @@ -394,7 +397,7 @@ static void test_readwrite_dead_faction_createunit(CuTest *tc) { u = r->units; CuAssertPtrNotNull(tc, u); CuAssertPtrEquals(tc, 0, a_find(u->attribs, &at_eventhandler)); - test_cleanup(); + test_teardown(); } static void test_read_password(CuTest *tc) { @@ -403,7 +406,7 @@ static void test_read_password(CuTest *tc) { faction *f; test_setup(); - f = test_create_faction(0); + f = test_create_faction(NULL); faction_setpassword(f, password_encode("secret", PASSWORD_DEFAULT)); mstream_init(&data.strm); gamedata_init(&data, &store, RELEASE_VERSION); @@ -413,7 +416,7 @@ static void test_read_password(CuTest *tc) { mstream_done(&data.strm); gamedata_done(&data); CuAssertTrue(tc, checkpasswd(f, "secret")); - test_cleanup(); + test_teardown(); } static void test_read_password_external(CuTest *tc) { @@ -427,7 +430,7 @@ static void test_read_password_external(CuTest *tc) { if (remove(pwfile) != 0) { errno = 0; } - f = test_create_faction(0); + f = test_create_faction(NULL); faction_setpassword(f, password_encode("secret", PASSWORD_DEFAULT)); CuAssertPtrNotNull(tc, f->_password); mstream_init(&data.strm); @@ -452,7 +455,7 @@ static void test_read_password_external(CuTest *tc) { mstream_done(&data.strm); gamedata_done(&data); CuAssertIntEquals(tc, 0, remove(pwfile)); - test_cleanup(); + test_teardown(); } static void test_version_no(CuTest *tc) { diff --git a/src/kernel/ship.c b/src/kernel/ship.c index 764500b50..d7e6238b1 100644 --- a/src/kernel/ship.c +++ b/src/kernel/ship.c @@ -36,11 +36,11 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* util includes */ #include #include -#include #include #include #include #include +#include #include #include @@ -125,7 +125,7 @@ ship_type *st_get_or_create(const char * name) { assert(!snames); if (!st) { st = (ship_type *)calloc(sizeof(ship_type), 1); - st->_name = strdup(name); + st->_name = str_strdup(name); st->storm = 1.0; st_register(st); } @@ -217,8 +217,8 @@ ship *new_ship(const ship_type * stype, region * r, const struct locale *lang) sname = parameters[P_SHIP]; } assert(sname); - slprintf(buffer, sizeof(buffer), "%s %s", sname, itoa36(sh->no)); - sh->name = strdup(buffer); + snprintf(buffer, sizeof(buffer), "%s %s", sname, itoa36(sh->no)); + sh->name = str_strdup(buffer); shash(sh); if (r) { addlist(&r->ships, sh); @@ -283,18 +283,34 @@ void free_ships(void) const char *write_shipname(const ship * sh, char *ibuf, size_t size) { - slprintf(ibuf, size, "%s (%s)", sh->name, itoa36(sh->no)); + snprintf(ibuf, size, "%s (%s)", sh->name, itoa36(sh->no)); return ibuf; } static int ShipSpeedBonus(const unit * u) { - int level = config_get_int("movement.shipspeed.skillbonus", 0); - if (level > 0) { - ship *sh = u->ship; + const ship * sh = u->ship; + static int config; + static int bonus; + + if (config_changed(&config)) { + bonus = config_get_int("movement.shipspeed.skillbonus", 0); + } + if (bonus > 0) { int skl = effskill(u, SK_SAILING, 0); int minsk = (sh->type->cptskill + 1) / 2; - return (skl - minsk) / level; + return (skl - minsk) / bonus; + } + else if (sh->type->flags & SFL_SPEEDY) { + int base = 3; + int speed = 0; + int minsk = sh->type->cptskill * base; + int skl = effskill(u, SK_SAILING, 0); + while (skl >= minsk) { + ++speed; + minsk *= base; + } + return speed; } return 0; } @@ -386,7 +402,7 @@ const char *shipname(const ship * sh) static name idbuf[8]; static int nextbuf = 0; char *ibuf = idbuf[(++nextbuf) % 8]; - return write_shipname(sh, ibuf, sizeof(name)); + return write_shipname(sh, ibuf, sizeof(idbuf[0])); } int shipcapacity(const ship * sh) @@ -476,7 +492,7 @@ void write_ship_reference(const struct ship *sh, struct storage *store) void ship_setname(ship * self, const char *name) { free(self->name); - self->name = name ? strdup(name) : 0; + self->name = name ? str_strdup(name) : 0; } const char *ship_getname(const ship * self) diff --git a/src/kernel/ship.h b/src/kernel/ship.h index 285c29cc0..2ee1a6d3b 100644 --- a/src/kernel/ship.h +++ b/src/kernel/ship.h @@ -34,6 +34,7 @@ extern "C" { #define SFL_OPENSEA 0x01 #define SFL_FLY 0x02 #define SFL_NOCOAST 0x04 +#define SFL_SPEEDY 0x08 typedef struct ship_type { char *_name; @@ -125,12 +126,12 @@ extern "C" { extern void free_ship(struct ship *s); extern void free_ships(void); - const char *ship_getname(const struct ship *self); + const char *ship_getname(const struct ship *sh); void ship_setname(struct ship *self, const char *name); int shipspeed(const struct ship *sh, const struct unit *u); int crew_skill(const struct ship *sh); - int ship_damage_percent(const struct ship *ship); + int ship_damage_percent(const struct ship *sh); #ifdef __cplusplus } #endif diff --git a/src/kernel/ship.test.c b/src/kernel/ship.test.c index ce55f55af..aa4dc5755 100644 --- a/src/kernel/ship.test.c +++ b/src/kernel/ship.test.c @@ -22,11 +22,12 @@ static void test_register_ship(CuTest * tc) { ship_type *stype; - test_cleanup(); + test_setup(); stype = st_get_or_create("herp"); CuAssertPtrNotNull(tc, stype); CuAssertPtrEquals(tc, stype, (void *)st_find("herp")); + test_teardown(); } static void test_ship_set_owner(CuTest * tc) @@ -38,7 +39,7 @@ static void test_ship_set_owner(CuTest * tc) const struct ship_type *stype; const struct race *human; - test_cleanup(); + test_setup(); test_create_world(); human = rc_find("human"); @@ -56,6 +57,7 @@ static void test_ship_set_owner(CuTest * tc) CuAssertPtrEquals(tc, u1, ship_owner(sh)); ship_set_owner(u2); CuAssertPtrEquals(tc, u2, ship_owner(sh)); + test_teardown(); } static void test_shipowner_goes_to_next_when_empty(CuTest * tc) @@ -67,7 +69,7 @@ static void test_shipowner_goes_to_next_when_empty(CuTest * tc) const struct ship_type *stype; const struct race *human; - test_cleanup(); + test_setup(); test_create_world(); human = rc_find("human"); @@ -90,6 +92,7 @@ static void test_shipowner_goes_to_next_when_empty(CuTest * tc) CuAssertPtrEquals(tc, u, ship_owner(sh)); u->number = 0; CuAssertPtrEquals(tc, u2, ship_owner(sh)); + test_teardown(); } static void test_shipowner_goes_to_other_when_empty(CuTest * tc) @@ -101,7 +104,7 @@ static void test_shipowner_goes_to_other_when_empty(CuTest * tc) const struct ship_type *stype; const struct race *human; - test_cleanup(); + test_setup(); test_create_world(); human = rc_find("human"); @@ -124,6 +127,7 @@ static void test_shipowner_goes_to_other_when_empty(CuTest * tc) CuAssertPtrEquals(tc, u, ship_owner(sh)); u->number = 0; CuAssertPtrEquals(tc, u2, ship_owner(sh)); + test_teardown(); } static void test_shipowner_goes_to_same_faction_when_empty(CuTest * tc) @@ -135,7 +139,7 @@ static void test_shipowner_goes_to_same_faction_when_empty(CuTest * tc) const struct ship_type *stype; const struct race *human; - test_cleanup(); + test_setup(); test_create_world(); human = rc_find("human"); @@ -163,6 +167,7 @@ static void test_shipowner_goes_to_same_faction_when_empty(CuTest * tc) CuAssertPtrEquals(tc, u3, ship_owner(sh)); u3->number = 0; CuAssertPtrEquals(tc, u2, ship_owner(sh)); + test_teardown(); } static void test_shipowner_goes_to_next_after_leave(CuTest * tc) @@ -174,7 +179,7 @@ static void test_shipowner_goes_to_next_after_leave(CuTest * tc) const struct ship_type *stype; const struct race *human; - test_cleanup(); + test_setup(); test_create_world(); human = rc_find("human"); @@ -197,6 +202,7 @@ static void test_shipowner_goes_to_next_after_leave(CuTest * tc) CuAssertPtrEquals(tc, u, ship_owner(sh)); leave_ship(u); CuAssertPtrEquals(tc, u2, ship_owner(sh)); + test_teardown(); } static void test_shipowner_goes_to_other_after_leave(CuTest * tc) @@ -208,7 +214,7 @@ static void test_shipowner_goes_to_other_after_leave(CuTest * tc) const struct ship_type *stype; const struct race *human; - test_cleanup(); + test_setup(); test_create_world(); human = rc_find("human"); @@ -231,6 +237,7 @@ static void test_shipowner_goes_to_other_after_leave(CuTest * tc) CuAssertPtrEquals(tc, u, ship_owner(sh)); leave_ship(u); CuAssertPtrEquals(tc, u2, ship_owner(sh)); + test_teardown(); } static void test_shipowner_goes_to_same_faction_after_leave(CuTest * tc) @@ -242,7 +249,7 @@ static void test_shipowner_goes_to_same_faction_after_leave(CuTest * tc) const struct ship_type *stype; const struct race *human; - test_cleanup(); + test_setup(); test_create_world(); human = rc_find("human"); @@ -272,6 +279,7 @@ static void test_shipowner_goes_to_same_faction_after_leave(CuTest * tc) CuAssertPtrEquals(tc, u2, ship_owner(sh)); leave_ship(u2); CuAssertPtrEquals(tc, 0, ship_owner(sh)); + test_teardown(); } static void test_shipowner_resets_when_empty(CuTest * tc) @@ -283,7 +291,7 @@ static void test_shipowner_resets_when_empty(CuTest * tc) const struct ship_type *stype; const struct race *human; - test_cleanup(); + test_setup(); test_create_world(); human = rc_find("human"); @@ -306,6 +314,7 @@ static void test_shipowner_resets_when_empty(CuTest * tc) CuAssertPtrEquals(tc, 0, ship_owner(sh)); u->number = 1; CuAssertPtrEquals(tc, u, ship_owner(sh)); + test_teardown(); } void test_shipowner_goes_to_empty_unit_after_leave(CuTest * tc) @@ -317,7 +326,7 @@ void test_shipowner_goes_to_empty_unit_after_leave(CuTest * tc) const struct ship_type *stype; const struct race *human; - test_cleanup(); + test_setup(); test_create_world(); human = rc_find("human"); @@ -347,11 +356,12 @@ void test_shipowner_goes_to_empty_unit_after_leave(CuTest * tc) CuAssertPtrEquals(tc, 0, ship_owner(sh)); u2->number = 1; CuAssertPtrEquals(tc, u2, ship_owner(sh)); + test_teardown(); } static void test_stype_defaults(CuTest *tc) { ship_type *stype; - test_cleanup(); + test_setup(); stype = st_get_or_create("hodor"); CuAssertPtrNotNull(tc, stype); CuAssertStrEquals(tc, "hodor", stype->_name); @@ -371,7 +381,7 @@ static void test_stype_defaults(CuTest *tc) { CuAssertIntEquals(tc, 0, stype->at_bonus); CuAssertIntEquals(tc, 0, stype->df_bonus); CuAssertIntEquals(tc, 0, stype->flags); - test_cleanup(); + test_teardown(); } static void test_crew_skill(CuTest *tc) { @@ -380,10 +390,10 @@ static void test_crew_skill(CuTest *tc) { struct faction *f; int i; - test_cleanup(); + test_setup(); test_create_world(); - r = findregion(0, 0); - f = test_create_faction(0); + r = test_create_region(0, 0, NULL); + f = test_create_faction(NULL); assert(r && f); sh = test_create_ship(r, st_find("boat")); for (i = 0; i != 4; ++i) { @@ -392,7 +402,7 @@ static void test_crew_skill(CuTest *tc) { u->ship = sh; } CuAssertIntEquals(tc, 20, crew_skill(sh)); - test_cleanup(); + test_teardown(); } static ship *setup_ship(void) { @@ -400,7 +410,7 @@ static ship *setup_ship(void) { ship_type *stype; config_set("movement.shipspeed.skillbonus", "0"); - r = test_create_region(0, 0, test_create_terrain("ocean", 0)); + r = test_create_ocean(0, 0); stype = test_create_shiptype("longboat"); stype->cptskill = 1; stype->sumskill = 10; @@ -411,7 +421,7 @@ static ship *setup_ship(void) { } static void setup_crew(ship *sh, struct faction *f, unit **cap, unit **crew) { - if (!f) f = test_create_faction(0); + if (!f) f = test_create_faction(NULL); assert(cap); assert(crew); *cap = test_create_unit(f, sh->region); @@ -422,11 +432,43 @@ static void setup_crew(ship *sh, struct faction *f, unit **cap, unit **crew) { set_level(*crew, SK_SAILING, sh->type->sumskill - sh->type->cptskill); } +static void test_shipspeed_speedy(CuTest *tc) { + ship_type *stype; + ship *sh; + unit *cap, *crw; + test_setup(); + stype = test_create_shiptype("dragonship"); + stype->range = 5; + stype->range_max = -1; + stype->flags |= SFL_SPEEDY; + cap = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); + crw = test_create_unit(cap->faction, cap->region); + sh = test_create_ship(cap->region, stype); + cap->ship = sh; + crw->ship = sh; + set_level(cap, SK_SAILING, stype->cptskill); + set_level(crw, SK_SAILING, stype->sumskill - stype->cptskill); + CuAssertPtrEquals(tc, cap, ship_owner(sh)); + CuAssertIntEquals(tc, 5, shipspeed(sh, cap)); + + set_level(cap, SK_SAILING, stype->cptskill * 3 - 1); + CuAssertIntEquals(tc, 5, shipspeed(sh, cap)); + set_level(cap, SK_SAILING, stype->cptskill * 3); + CuAssertIntEquals(tc, 6, shipspeed(sh, cap)); + + set_level(cap, SK_SAILING, stype->cptskill * 3 * 3 - 1); + CuAssertIntEquals(tc, 6, shipspeed(sh, cap)); + set_level(cap, SK_SAILING, stype->cptskill * 3 * 3); + CuAssertIntEquals(tc, 7, shipspeed(sh, cap)); + + test_teardown(); +} + static void test_shipspeed_stormwind(CuTest *tc) { ship *sh; unit *cap, *crew; - test_cleanup(); + test_setup(); sh = setup_ship(); setup_crew(sh, 0, &cap, &crew); register_shipcurse(); @@ -437,14 +479,14 @@ static void test_shipspeed_stormwind(CuTest *tc) { CuAssertIntEquals_Msg(tc, "stormwind doubles ship range", sh->type->range * 2, shipspeed(sh, cap)); a_age(&sh->attribs, sh); CuAssertPtrEquals(tc, NULL, sh->attribs); - test_cleanup(); + test_teardown(); } static void test_shipspeed_nodrift(CuTest *tc) { ship *sh; unit *cap, *crew; - test_cleanup(); + test_setup(); sh = setup_ship(); setup_crew(sh, 0, &cap, &crew); register_shipcurse(); @@ -452,14 +494,14 @@ static void test_shipspeed_nodrift(CuTest *tc) { create_curse(0, &sh->attribs, &ct_nodrift, 1, 1, 1, 0); CuAssertIntEquals_Msg(tc, "nodrift adds +1 to range", sh->type->range + 1, shipspeed(sh, cap)); - test_cleanup(); + test_teardown(); } static void test_shipspeed_shipspeedup(CuTest *tc) { ship *sh; unit *cap, *crew; - test_cleanup(); + test_setup(); sh = setup_ship(); setup_crew(sh, 0, &cap, &crew); register_shipcurse(); @@ -467,7 +509,7 @@ static void test_shipspeed_shipspeedup(CuTest *tc) { create_curse(0, &sh->attribs, &ct_shipspeedup, 1, 1, 3, 0); CuAssertIntEquals_Msg(tc, "shipspeedup adds effect to range", sh->type->range + 3, shipspeed(sh, cap)); - test_cleanup(); + test_teardown(); } static void test_shipspeed_at_speedup(CuTest *tc) { @@ -475,7 +517,7 @@ static void test_shipspeed_at_speedup(CuTest *tc) { unit *cap, *crew; attrib *a; - test_cleanup(); + test_setup(); sh = setup_ship(); setup_crew(sh, 0, &cap, &crew); assert(sh && cap && crew); @@ -484,7 +526,7 @@ static void test_shipspeed_at_speedup(CuTest *tc) { a->data.i = 3; a_add(&sh->attribs, a); CuAssertIntEquals_Msg(tc, "at_speedup adds value to range", sh->type->range + 3, shipspeed(sh, cap)); - test_cleanup(); + test_teardown(); } static void test_shipspeed_race_bonus(CuTest *tc) { @@ -492,7 +534,7 @@ static void test_shipspeed_race_bonus(CuTest *tc) { unit *cap, *crew; race *rc; - test_cleanup(); + test_setup(); sh = setup_ship(); setup_crew(sh, 0, &cap, &crew); assert(sh && cap && crew); @@ -500,14 +542,14 @@ static void test_shipspeed_race_bonus(CuTest *tc) { rc = rc_get_or_create(cap->_race->_name); rc->flags |= RCF_SHIPSPEED; CuAssertIntEquals_Msg(tc, "captain with RCF_SHIPSPEED adds +1 to range", sh->type->range + 1, shipspeed(sh, cap)); - test_cleanup(); + test_teardown(); } static void test_shipspeed_damage(CuTest *tc) { ship *sh; unit *cap, *crew; - test_cleanup(); + test_setup(); sh = setup_ship(); setup_crew(sh, 0, &cap, &crew); assert(sh && cap && crew); @@ -518,7 +560,7 @@ static void test_shipspeed_damage(CuTest *tc) { CuAssertIntEquals_Msg(tc, "damaged ships lose range", 1, shipspeed(sh, cap)); sh->damage = sh->size * DAMAGE_SCALE; CuAssertIntEquals_Msg(tc, "fully damaged ships have no range", 0, shipspeed(sh, cap)); - test_cleanup(); + test_teardown(); } static void test_shipspeed(CuTest *tc) { @@ -526,7 +568,7 @@ static void test_shipspeed(CuTest *tc) { const ship_type *stype; unit *cap, *crew; - test_cleanup(); + test_setup(); sh = setup_ship(); stype = sh->type; @@ -549,6 +591,7 @@ static void test_shipspeed(CuTest *tc) { set_level(crew, SK_SAILING, (stype->sumskill - stype->cptskill) * 11); set_level(cap, SK_SAILING, stype->cptskill + 10); CuAssertIntEquals_Msg(tc, "regular skills should not exceed sh.range", 2, shipspeed(sh, cap)); + test_teardown(); } static void test_shipspeed_max_range(CuTest *tc) { @@ -558,12 +601,12 @@ static void test_shipspeed_max_range(CuTest *tc) { struct faction *f; unit *cap, *crew; - test_cleanup(); + test_setup(); sh = setup_ship(); setup_crew(sh, 0, &cap, &crew); config_set("movement.shipspeed.skillbonus", "5"); r = sh->region; - f = test_create_faction(0); + f = test_create_faction(NULL); assert(r && f); stype = st_get_or_create(sh->type->_name); @@ -576,9 +619,10 @@ static void test_shipspeed_max_range(CuTest *tc) { CuAssertIntEquals_Msg(tc, "skill bonus from movement.shipspeed.skillbonus", 3, shipspeed(sh, cap)); set_level(cap, SK_SAILING, stype->cptskill + 15); - set_level(crew, SK_SAILING, (stype->sumskill - stype->cptskill) * 15); + scale_number(crew, 15); + set_level(crew, SK_SAILING, stype->sumskill - stype->cptskill); CuAssertIntEquals_Msg(tc, "skill-bonus cannot exceed max_range", 4, shipspeed(sh, cap)); - test_cleanup(); + test_teardown(); } CuSuite *get_ship_suite(void) @@ -597,6 +641,7 @@ CuSuite *get_ship_suite(void) SUITE_ADD_TEST(suite, test_shipowner_goes_to_empty_unit_after_leave); SUITE_ADD_TEST(suite, test_crew_skill); SUITE_ADD_TEST(suite, test_shipspeed); + SUITE_ADD_TEST(suite, test_shipspeed_speedy); SUITE_ADD_TEST(suite, test_shipspeed_stormwind); SUITE_ADD_TEST(suite, test_shipspeed_nodrift); SUITE_ADD_TEST(suite, test_shipspeed_shipspeedup); diff --git a/src/kernel/skills.c b/src/kernel/skills.c index 3bcbd0f66..8c4b4d2a6 100644 --- a/src/kernel/skills.c +++ b/src/kernel/skills.c @@ -178,6 +178,7 @@ void sk_set(skill * sv, int level) assert(sv && level != 0); sv->weeks = skill_weeks(level); sv->level = level; + assert(sv->weeks <= sv->level * 2 + 1); } static bool rule_random_progress(void) @@ -203,30 +204,40 @@ int skill_weeks(int level) return level + 1; } -void increase_skill(unit * u, skill_t sk, unsigned int weeks) +void increase_skill(unit * u, skill_t sk, int weeks) { skill *sv = unit_skill(u, sk); + assert(weeks >= 0); if (!sv) { sv = add_skill(u, sk); } - while (sv->weeks <= (int) weeks) { + while (sv->weeks <= weeks) { weeks -= sv->weeks; sk_set(sv, sv->level + 1); } sv->weeks -= weeks; + assert(sv->weeks <= sv->level * 2 + 1); } -void reduce_skill(unit * u, skill * sv, unsigned int weeks) +void reduce_skill(unit * u, skill * sv, int weeks) { + int max_weeks = sv->level + 1; + + assert(weeks >= 0); + if (rule_random_progress()) { + max_weeks += sv->level; + } sv->weeks += weeks; - while (sv->level > 0 && sv->level * 2 + 1 < sv->weeks) { + while (sv->level > 0 && sv->weeks > max_weeks) { sv->weeks -= sv->level; --sv->level; + max_weeks -= 2; } if (sv->level == 0) { /* reroll */ - sv->weeks = (unsigned char)skill_weeks(sv->level); + sv->weeks = skill_weeks(sv->level); } + assert(sv->weeks <= sv->level * 2 + 1); } int skill_compare(const skill * sk, const skill * sc) diff --git a/src/kernel/skills.h b/src/kernel/skills.h index 4c41109d7..649fa92cf 100644 --- a/src/kernel/skills.h +++ b/src/kernel/skills.h @@ -26,10 +26,10 @@ extern "C" { #endif typedef struct skill { - skill_t id; - int level; - int weeks; - int old; + skill_t id : 8; + int level : 8; + int weeks : 8; + int old : 8; } skill; typedef int(*skillmod_fun) (const struct unit *, const struct region *, @@ -52,8 +52,8 @@ extern "C" { int level(int days); #define skill_level(level) (level) - void increase_skill(struct unit * u, skill_t sk, unsigned int weeks); - void reduce_skill(struct unit *u, skill * sv, unsigned int weeks); + void increase_skill(struct unit * u, skill_t sk, int weeks); + void reduce_skill(struct unit *u, skill * sv, int weeks); int skill_weeks(int level); int skill_compare(const skill * sk, const skill * sc); diff --git a/src/kernel/skills.test.c b/src/kernel/skills.test.c new file mode 100644 index 000000000..c7a57e4d8 --- /dev/null +++ b/src/kernel/skills.test.c @@ -0,0 +1,41 @@ +#ifdef _MSC_VER +#include +#endif +#include "skills.h" + +#include "config.h" +#include "unit.h" + +#include +#include + +static void test_skills(CuTest * tc) +{ + unit *u; + + test_setup(); + config_set_int("study.random_progress", 0); + u = test_create_unit(test_create_faction(NULL), test_create_plain(0, 0)); + CuAssertPtrEquals(tc, NULL, u->skills); + CuAssertIntEquals(tc, 0, u->skill_size); + CuAssertIntEquals(tc, 0, get_level(u, SK_CROSSBOW)); + set_level(u, SK_CROSSBOW, 1); + CuAssertPtrNotNull(tc, u->skills); + CuAssertIntEquals(tc, 1, u->skill_size); + CuAssertIntEquals(tc, SK_CROSSBOW, u->skills->id); + CuAssertIntEquals(tc, 1, u->skills->level); + CuAssertIntEquals(tc, 2, u->skills->weeks); + CuAssertIntEquals(tc, 1, get_level(u, SK_CROSSBOW)); + set_level(u, SK_CROSSBOW, 0); + CuAssertPtrEquals(tc, NULL, u->skills); + CuAssertIntEquals(tc, 0, u->skill_size); + test_teardown(); +} + +CuSuite *get_skills_suite(void) +{ + CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_skills); + return suite; +} + diff --git a/src/kernel/spell.c b/src/kernel/spell.c index 0abb487f7..ca97bf1f0 100644 --- a/src/kernel/spell.c +++ b/src/kernel/spell.c @@ -16,8 +16,9 @@ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. **/ +#ifdef _MSC_VER #include -#include +#endif #include "spell.h" /* util includes */ @@ -25,6 +26,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include #include #include @@ -124,7 +126,7 @@ spell * create_spell(const char * name) sp = (spell *)calloc(1, sizeof(spell)); len = cb_new_kv(name, len, &sp, sizeof(sp), buffer); if (cb_insert(&cb_spells, buffer, len) == CB_SUCCESS) { - sp->sname = strdup(name); + sp->sname = str_strdup(name); add_spell(&spells, sp); return sp; } @@ -173,10 +175,10 @@ struct spellref *spellref_create(spell *sp, const char *name) if (sp) { spref->sp = sp; - spref->name = strdup(sp->sname); + spref->name = str_strdup(sp->sname); } else if (name) { - spref->name = strdup(name); + spref->name = str_strdup(name); spref->sp = NULL; } return spref; diff --git a/src/kernel/spell.test.c b/src/kernel/spell.test.c index e5a37fd65..5502069d1 100644 --- a/src/kernel/spell.test.c +++ b/src/kernel/spell.test.c @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -22,7 +23,7 @@ static void test_create_a_spell(CuTest * tc) sp = create_spell("testspell"); CuAssertPtrEquals(tc, sp, find_spell("testspell")); CuAssertPtrNotNull(tc, spells); - test_cleanup(); + test_teardown(); } static void test_create_duplicate_spell(CuTest * tc) @@ -32,7 +33,8 @@ static void test_create_duplicate_spell(CuTest * tc) strlist *sl = 0; test_setup(); - test_log_stderr(0); + test_inject_messagetypes(); + test_log_stderr(0); /* suppress the "duplicate spell" error message */ log = test_log_start(LOG_CPERROR, &sl); CuAssertPtrEquals(tc, 0, find_spell("testspell")); @@ -44,7 +46,8 @@ static void test_create_duplicate_spell(CuTest * tc) CuAssertPtrEquals(tc, 0, sl->next); CuAssertPtrEquals(tc, sp, find_spell("testspell")); test_log_stop(log, sl); - test_cleanup(); + test_log_stderr(1); /* or teardown complains that stderr logging is off */ + test_teardown(); } static void test_spellref(CuTest *tc) @@ -61,7 +64,7 @@ static void test_spellref(CuTest *tc) CuAssertPtrNotNull(tc, sp); CuAssertPtrEquals(tc, sp, spellref_get(ref)); spellref_free(ref); - test_cleanup(); + test_teardown(); } void fumble_foo(const struct castorder *co) { @@ -81,7 +84,7 @@ static void test_fumbles(CuTest *tc) CuAssertTrue(tc, fumble_foo==get_fumble("foone")); CuAssertTrue(tc, fumble_bar==get_fumble("foozle")); CuAssertTrue(tc, NULL==get_fumble("foo")); - test_cleanup(); + test_teardown(); } CuSuite *get_spell_suite(void) diff --git a/src/kernel/spellbook.c b/src/kernel/spellbook.c index b7f65420c..ae5387f11 100644 --- a/src/kernel/spellbook.c +++ b/src/kernel/spellbook.c @@ -1,12 +1,15 @@ +#ifdef _MSC_VER #include -#include +#endif #include -#include + #include #include +#include #include "spellbook.h" +#include #include #include @@ -16,7 +19,7 @@ spellbook * create_spellbook(const char * name) { spellbook *result = (spellbook *)malloc(sizeof(spellbook)); - result->name = name ? strdup(name) : 0; + result->name = name ? str_strdup(name) : 0; result->spells = 0; return result; } diff --git a/src/kernel/terrain.c b/src/kernel/terrain.c index e9f448f97..5a46b7fe7 100644 --- a/src/kernel/terrain.c +++ b/src/kernel/terrain.c @@ -31,15 +31,14 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include +#include /* libc includes */ #include #include #include -#define MAXTERRAINS 14 - -const char *terraindata[MAXTERRAINS] = { +static const char *terrainnames[MAXTERRAINS] = { "ocean", "plain", "swamp", @@ -57,6 +56,17 @@ const char *terraindata[MAXTERRAINS] = { }; static terrain_type *registered_terrains; +static int terrain_changes = 1; + +bool terrain_changed(int *cache) { + assert(cache); + if (*cache != terrain_changes) { + *cache = terrain_changes; + return true; + } + return false; +} + void free_terrains(void) { @@ -76,6 +86,7 @@ void free_terrains(void) } free(t); } + ++terrain_changes; } const terrain_type *terrains(void) @@ -110,9 +121,10 @@ const terrain_type *get_terrain(const char *name) { terrain_type * get_or_create_terrain(const char *name) { terrain_type *terrain = terrain_find_i(name); if (!terrain) { + ++terrain_changes; terrain = (terrain_type *)calloc(sizeof(terrain_type), 1); if (terrain) { - terrain->_name = strdup(name); + terrain->_name = str_strdup(name); terrain->next = registered_terrains; registered_terrains = terrain; if (strcmp("plain", name) == 0) { @@ -128,11 +140,20 @@ static const terrain_type *newterrains[MAXTERRAINS]; const struct terrain_type *newterrain(terrain_t t) { - if (t == NOTERRAIN) + const struct terrain_type *result; + if (t == NOTERRAIN) { return NULL; + } assert(t >= 0); assert(t < MAXTERRAINS); - return newterrains[t]; + result = newterrains[t]; + if (!result) { + result = newterrains[t] = get_terrain(terrainnames[t]); + } + if (!result) { + log_error("no such terrain: %s.", terrainnames[t]); + } + return result; } terrain_t oldterrain(const struct terrain_type * terrain) @@ -176,8 +197,8 @@ void init_terrains(void) const terrain_type *newterrain = newterrains[t]; if (newterrain != NULL) continue; - if (terraindata[t] != NULL) { - newterrain = get_terrain(terraindata[t]); + if (terrainnames[t] != NULL) { + newterrain = get_terrain(terrainnames[t]); if (newterrain != NULL) { newterrains[t] = newterrain; } diff --git a/src/kernel/terrain.h b/src/kernel/terrain.h index 3d1491867..26c509f75 100644 --- a/src/kernel/terrain.h +++ b/src/kernel/terrain.h @@ -18,6 +18,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #ifndef TERRAIN_H #define TERRAIN_H + #ifdef __cplusplus extern "C" { #endif @@ -68,12 +69,13 @@ extern "C" { struct terrain_type *next; } terrain_type; - extern terrain_type *get_or_create_terrain(const char *name); - extern const terrain_type *terrains(void); - extern const terrain_type *get_terrain(const char *name); - extern const char *terrain_name(const struct region *r); + terrain_type *get_or_create_terrain(const char *name); + const terrain_type *terrains(void); + const terrain_type *get_terrain(const char *name); + const char *terrain_name(const struct region *r); + bool terrain_changed(int *cache); - extern void init_terrains(void); + void init_terrains(void); void free_terrains(void); #ifdef __cplusplus diff --git a/src/kernel/terrainid.h b/src/kernel/terrainid.h index 7d353d042..b6235c399 100644 --- a/src/kernel/terrainid.h +++ b/src/kernel/terrainid.h @@ -14,7 +14,7 @@ extern "C" { #endif - enum { + typedef enum { T_OCEAN = 0, T_PLAIN, T_SWAMP, @@ -29,8 +29,9 @@ extern "C" { T_VOLCANO_SMOKING, T_ICEBERG_SLEEP, T_ICEBERG, - NOTERRAIN = (terrain_t) - 1 - }; + MAXTERRAINS, + NOTERRAIN = - 1 + } terrain_t; extern const struct terrain_type *newterrain(terrain_t t); extern terrain_t oldterrain(const struct terrain_type *terrain); diff --git a/src/kernel/types.h b/src/kernel/types.h index a20e923d6..9e9ed3b66 100644 --- a/src/kernel/types.h +++ b/src/kernel/types.h @@ -22,7 +22,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include -typedef short terrain_t; typedef short item_t; struct attrib; diff --git a/src/kernel/unit.c b/src/kernel/unit.c index 9b024851b..367ea4d97 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -51,17 +51,18 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* util includes */ #include #include -#include #include #include #include #include #include #include +#include #include #include #include #include +#include #include #include @@ -394,11 +395,14 @@ faction *dfindhash(int no) } #else struct faction *dfindhash(int no) { - unit *u = deleted_units; - while (u && u->no != no) { - u = u->next; + unit *u; + + for (u = deleted_units; u; u = u->next) { + if (u->no == no) { + return u->faction; + } } - return u ? u->faction : NULL; + return NULL; } #endif @@ -507,7 +511,7 @@ int a_readprivate(attrib * a, void *owner, gamedata *data) struct storage *store = data->store; char lbuf[DISPLAYSIZE]; READ_STR(store, lbuf, sizeof(lbuf)); - a->data.v = strdup(lbuf); + a->data.v = str_strdup(lbuf); return (a->data.v) ? AT_READ_OK : AT_READ_FAIL; } @@ -565,7 +569,7 @@ void usetprivate(unit * u, const char *str) if (a->data.v) { free(a->data.v); } - a->data.v = strdup(str); + a->data.v = str_strdup(str); } /*********************/ @@ -581,7 +585,7 @@ attrib_type at_potionuser = { NO_READ }; -void usetpotionuse(unit * u, const potion_type * ptype) +void usetpotionuse(unit * u, const item_type * ptype) { attrib *a = a_find(u->attribs, &at_potionuser); if (!a) @@ -589,12 +593,12 @@ void usetpotionuse(unit * u, const potion_type * ptype) a->data.v = (void *)ptype; } -const potion_type *ugetpotionuse(const unit * u) +const item_type *ugetpotionuse(const unit * u) { attrib *a = a_find(u->attribs, &at_potionuser); if (!a) return NULL; - return (const potion_type *)a->data.v; + return (const item_type *)a->data.v; } /*********************/ @@ -791,6 +795,7 @@ void set_level(unit * u, skill_t sk, int value) skill *sv = u->skills; assert(sk != SK_MAGIC || !u->faction || u->number == 1 || fval(u->faction, FFL_NPC)); + assert(value <= CHAR_MAX && value >= CHAR_MIN); if (!skill_enabled(sk)) return; @@ -1194,8 +1199,13 @@ void remove_skill(unit * u, skill_t sk) for (i = 0; i != u->skill_size; ++i) { sv = u->skills + i; if (sv->id == sk) { - memmove(sv, sv + 1, (u->skill_size - i - 1) * sizeof(skill)); - --u->skill_size; + if (u->skill_size - i - 1 > 0) { + memmove(sv, sv + 1, (u->skill_size - i - 1) * sizeof(skill)); + } + if (--u->skill_size == 0) { + free(u->skills); + u->skills = NULL; + } return; } } @@ -1455,9 +1465,7 @@ void default_name(const unit *u, char name[], int len) { else { result = parameters[P_UNIT]; } - strlcpy(name, result, len); - strlcat(name, " ", len); - strlcat(name, itoa36(u->no), len); + snprintf(name, len, "%s %s", result, itoa36(u->no)); } void name_unit(unit * u) @@ -1512,7 +1520,7 @@ unit *create_unit(region * r, faction * f, int number, const struct race *urace, } if (dname) { - u->_name = strdup(dname); + u->_name = str_strdup(dname); } else if (urace->name_unit || playerrace(urace)) { name_unit(u); @@ -1597,12 +1605,6 @@ int countheroes(const struct faction *f) n += u->number; u = u->nextF; } -#ifdef DEBUG_MAXHEROES - int m = maxheroes(f); - if (n > m) { - log_warning("%s has %d of %d heroes\n", factionname(f), n, m); - } -#endif return n; } @@ -1621,7 +1623,7 @@ void unit_setname(unit * u, const char *name) { free(u->_name); if (name && name[0]) - u->_name = strdup(name); + u->_name = str_strdup(name); else u->_name = NULL; } @@ -1635,7 +1637,7 @@ void unit_setinfo(unit * u, const char *info) { free(u->display); if (info) - u->display = strdup(info); + u->display = str_strdup(info); else u->display = NULL; } @@ -1708,7 +1710,6 @@ void unit_addorder(unit * u, order * ord) int unit_max_hp(const unit * u) { int h; - double p; static int config; static bool rule_stamina; h = u_race(u)->hitpoints; @@ -1717,7 +1718,7 @@ int unit_max_hp(const unit * u) rule_stamina = config_get_int("rules.stamina", 1)!=0; } if (rule_stamina) { - p = pow(effskill(u, SK_STAMINA, u->region) / 2.0, 1.5) * 0.2; + double p = pow(effskill(u, SK_STAMINA, u->region) / 2.0, 1.5) * 0.2; h += (int)(h * p + 0.5); } @@ -1733,38 +1734,22 @@ int unit_max_hp(const unit * u) void scale_number(unit * u, int n) { - const attrib *a; - int remain; - - if (n == u->number) + if (n == u->number) { return; - if (n && u->number > 0) { - int full; - remain = ((u->hp % u->number) * (n % u->number)) % u->number; - - full = u->hp / u->number; /* wieviel kriegt jede person mindestens */ - u->hp = full * n + (u->hp - full * u->number) * n / u->number; - assert(u->hp >= 0); - if ((rng_int() % u->number) < remain) - ++u->hp; /* Nachkommastellen */ - } - else { - remain = 0; - u->hp = 0; } if (u->number > 0) { - for (a = a_find(u->attribs, &at_effect); a && a->type == &at_effect; - a = a->next) { - effect_data *data = (effect_data *)a->data.v; - int snew = data->value / u->number * n; - if (n) { - remain = data->value - snew / n * u->number; - snew += remain * n / u->number; - remain = (remain * n) % u->number; - if ((rng_int() % u->number) < remain) - ++snew; /* Nachkommastellen */ + if (n>0) { + const attrib *a = a_find(u->attribs, &at_effect); + + u->hp = (long long)u->hp * n / u->number; + + for (; a && a->type == &at_effect; a = a->next) { + effect_data *data = (effect_data *)a->data.v; + data->value = (long long)data->value * n / u->number; } - data->value = snew; + } + else { + u->hp = 0; } } if (u->number == 0 || n == 0) { @@ -1894,7 +1879,7 @@ static int nextbuf = 0; char *write_unitname(const unit * u, char *buffer, size_t size) { const char * name = unit_getname(u); - slprintf(buffer, size, "%s (%s)", name, itoa36(u->no)); + snprintf(buffer, size, "%s (%s)", name, itoa36(u->no)); buffer[size - 1] = 0; return buffer; } @@ -1903,7 +1888,7 @@ char *write_unitname(const unit * u, char *buffer, size_t size) const char *unitname(const unit * u) { char *ubuf = idbuf[(++nextbuf) % 8]; - return write_unitname(u, ubuf, sizeof(name)); + return write_unitname(u, ubuf, sizeof(idbuf[0])); } bool unit_name_equals_race(const unit *u) { @@ -1945,10 +1930,6 @@ int read_unitid(const faction * f, const region * r) char token[16]; const char *s = gettoken(token, sizeof(token)); - /* Da s nun nur einen string enthaelt, suchen wir ihn direkt in der - * paramliste. machen wir das nicht, dann wird getnewunit in s nach der - * nummer suchen, doch dort steht bei temp-units nur "temp" drinnen! */ - if (!s || *s == 0 || !isalnum(*s)) { return -1; } diff --git a/src/kernel/unit.h b/src/kernel/unit.h index d80c0ec79..91a3ec930 100644 --- a/src/kernel/unit.h +++ b/src/kernel/unit.h @@ -28,11 +28,14 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -#define MAXUNITS 1048573 /* must be prime for hashing. 524287 was >90% full */ struct skill; struct item; struct sc_mage; struct gamedata; + struct item_type; + +#define MAXUNITS 1048573 /* should be prime for hashing. 524287 was >90% full */ + #define UFL_DEAD (1<<0) #define UFL_ISNEW (1<<1) /* 2 */ #define UFL_LONGACTION (1<<2) /* 4 */ @@ -112,7 +115,7 @@ extern "C" { int flags; struct attrib *attribs; status_t status; - int n; /* helper temporariy variable, used in econmy, enno: attribut? */ + int n; /* helper temporary variable, used in economy, enno: attribut? */ int wants; /* enno: attribut? */ } unit; @@ -147,8 +150,8 @@ extern "C" { const char *uprivate(const struct unit *u); void usetprivate(struct unit *u, const char *c); - const struct potion_type *ugetpotionuse(const struct unit *u); /* benutzt u einein trank? */ - void usetpotionuse(struct unit *u, const struct potion_type *p); /* u benutzt trank p (es darf halt nur einer pro runde) */ + const struct item_type *ugetpotionuse(const struct unit *u); /* benutzt u einein trank? */ + void usetpotionuse(struct unit *u, const struct item_type *p); /* u benutzt trank p (es darf halt nur einer pro runde) */ bool ucontact(const struct unit *u, const struct unit *u2); void usetcontact(struct unit *u, const struct unit *c); diff --git a/src/kernel/unit.test.c b/src/kernel/unit.test.c index 0dcddcd5a..20d23e7a8 100644 --- a/src/kernel/unit.test.c +++ b/src/kernel/unit.test.c @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include #include #include @@ -41,7 +43,7 @@ static void test_remove_empty_units(CuTest *tc) { u->number = 0; remove_empty_units(); CuAssertPtrEquals(tc, 0, findunit(uid)); - test_cleanup(); + test_teardown(); } static void test_remove_empty_units_in_region(CuTest *tc) { @@ -62,7 +64,7 @@ static void test_remove_empty_units_in_region(CuTest *tc) { CuAssertPtrEquals(tc, 0, findunit(uid)); CuAssertPtrEquals(tc, 0, u->nextF); CuAssertPtrEquals(tc, 0, u->region); - test_cleanup(); + test_teardown(); } static void test_remove_units_without_faction(CuTest *tc) { @@ -78,7 +80,7 @@ static void test_remove_units_without_faction(CuTest *tc) { remove_empty_units_in_region(u->region); CuAssertPtrEquals(tc, 0, findunit(uid)); CuAssertIntEquals(tc, 0, u->number); - test_cleanup(); + test_teardown(); } static void test_remove_units_with_dead_faction(CuTest *tc) { @@ -94,29 +96,38 @@ static void test_remove_units_with_dead_faction(CuTest *tc) { remove_empty_units_in_region(u->region); CuAssertPtrEquals(tc, 0, findunit(uid)); CuAssertIntEquals(tc, 0, u->number); - test_cleanup(); + test_teardown(); } static void test_scale_number(CuTest *tc) { unit *u; - const struct potion_type *ptype; + const struct item_type *ptype; test_setup(); test_create_world(); - ptype = new_potiontype(it_get_or_create(rt_get_or_create("hodor")), 1); + ptype = it_get_or_create(rt_get_or_create("hodor")); u = test_create_unit(test_create_faction(test_create_race("human")), findregion(0, 0)); change_effect(u, ptype, 1); + u->hp = 35; CuAssertIntEquals(tc, 1, u->number); - CuAssertIntEquals(tc, 20, u->hp); + CuAssertIntEquals(tc, 35, u->hp); CuAssertIntEquals(tc, 1, get_effect(u, ptype)); scale_number(u, 2); CuAssertIntEquals(tc, 2, u->number); - CuAssertIntEquals(tc, 40, u->hp); - CuAssertIntEquals(tc, 2, get_effect(u, ptype)); + CuAssertIntEquals(tc, 35 * u->number, u->hp); + CuAssertIntEquals(tc, u->number, get_effect(u, ptype)); + scale_number(u, 8237); + CuAssertIntEquals(tc, 8237, u->number); + CuAssertIntEquals(tc, 35 * u->number, u->hp); + CuAssertIntEquals(tc, u->number, get_effect(u, ptype)); + scale_number(u, 8100); + CuAssertIntEquals(tc, 8100, u->number); + CuAssertIntEquals(tc, 35 * u->number, u->hp); + CuAssertIntEquals(tc, u->number, get_effect(u, ptype)); set_level(u, SK_ALCHEMY, 1); scale_number(u, 0); CuAssertIntEquals(tc, 0, get_level(u, SK_ALCHEMY)); - test_cleanup(); + test_teardown(); } static void test_unit_name(CuTest *tc) { @@ -128,7 +139,7 @@ static void test_unit_name(CuTest *tc) { renumber_unit(u, 666); unit_setname(u, "Hodor"); CuAssertStrEquals(tc, "Hodor (ii)", unitname(u)); - test_cleanup(); + test_teardown(); } static void test_unit_name_from_race(CuTest *tc) { @@ -146,7 +157,7 @@ static void test_unit_name_from_race(CuTest *tc) { CuAssertStrEquals(tc, "human_p (ii)", unitname(u)); CuAssertStrEquals(tc, "human_p", unit_getname(u)); - test_cleanup(); + test_teardown(); } static void test_update_monster_name(CuTest *tc) { @@ -172,13 +183,13 @@ static void test_update_monster_name(CuTest *tc) { unit_setname(u, rc_name_s(u->_race, NAME_PLURAL)); CuAssertTrue(tc, unit_name_equals_race(u)); - test_cleanup(); + test_teardown(); } static void test_names(CuTest *tc) { unit *u; - test_cleanup(); + test_setup(); test_create_world(); u = test_create_unit(test_create_faction(test_create_race("human")), findregion(0, 0)); @@ -186,7 +197,7 @@ static void test_names(CuTest *tc) { unit_setid(u, 5); CuAssertStrEquals(tc, "Hodor", unit_getname(u)); CuAssertStrEquals(tc, "Hodor (5)", unitname(u)); - test_cleanup(); + test_teardown(); } static void test_default_name(CuTest *tc) { @@ -206,7 +217,7 @@ static void test_default_name(CuTest *tc) { sprintf(compare, "Zweiheit %s", itoa36(u->no)); CuAssertStrEquals(tc, compare, buf); - test_cleanup(); + test_teardown(); } static int cb_skillmod(const unit *u, const region *r, skill_t sk, int level) { @@ -220,8 +231,8 @@ static void test_skillmod(CuTest *tc) { unit *u; attrib *a; - test_cleanup(); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + test_setup(); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); set_level(u, SK_ARMORER, 5); CuAssertIntEquals(tc, 5, effskill(u, SK_ARMORER, 0)); @@ -241,14 +252,14 @@ static void test_skillmod(CuTest *tc) { CuAssertIntEquals(tc, 8, effskill(u, SK_ARMORER, 0)); a_remove(&u->attribs, a); - test_cleanup(); + test_teardown(); } static void test_skill_hunger(CuTest *tc) { unit *u; - test_cleanup(); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + test_setup(); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); set_level(u, SK_ARMORER, 6); set_level(u, SK_SAILING, 6); fset(u, UFL_HUNGER); @@ -256,18 +267,18 @@ static void test_skill_hunger(CuTest *tc) { CuAssertIntEquals(tc, 5, effskill(u, SK_SAILING, 0)); set_level(u, SK_SAILING, 2); CuAssertIntEquals(tc, 1, effskill(u, SK_SAILING, 0)); - test_cleanup(); + test_teardown(); } static void test_skill_familiar(CuTest *tc) { unit *mag, *fam; region *r; - test_cleanup(); + test_setup(); /* setup two units */ - mag = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); - fam = test_create_unit(mag->faction, test_create_region(0, 0, 0)); + mag = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); + fam = test_create_unit(mag->faction, test_create_region(0, 0, NULL)); set_level(fam, SK_PERCEPTION, 6); CuAssertIntEquals(tc, 6, effskill(fam, SK_PERCEPTION, 0)); set_level(mag, SK_PERCEPTION, 6); @@ -284,7 +295,7 @@ static void test_skill_familiar(CuTest *tc) { r = test_create_region(3, 0, 0); move_unit(fam, r, &r->units); CuAssertIntEquals(tc, 7, effskill(mag, SK_PERCEPTION, 0)); - test_cleanup(); + test_teardown(); } static void test_inside_building(CuTest *tc) { @@ -292,8 +303,8 @@ static void test_inside_building(CuTest *tc) { building *b; test_setup(); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); - b = test_create_building(u->region, 0); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); + b = test_create_building(u->region, NULL); b->size = 1; scale_number(u, 1); @@ -309,14 +320,14 @@ static void test_inside_building(CuTest *tc) { CuAssertPtrEquals(tc, 0, inside_building(u)); b->size = 3; CuAssertPtrEquals(tc, b, inside_building(u)); - test_cleanup(); + test_teardown(); } static void test_skills(CuTest *tc) { unit *u; skill *sv; test_setup(); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); sv = add_skill(u, SK_ALCHEMY); CuAssertPtrNotNull(tc, sv); CuAssertPtrEquals(tc, sv, u->skills); @@ -350,13 +361,14 @@ static void test_skills(CuTest *tc) { CuAssertIntEquals(tc, SK_ALCHEMY, u->skills[0].id); CuAssertIntEquals(tc, 1, u->skill_size); CuAssertTrue(tc, !has_skill(u, SK_LONGBOW)); - test_cleanup(); + test_teardown(); } static void test_limited_skills(CuTest *tc) { unit *u; + test_setup(); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); CuAssertIntEquals(tc, false, has_limited_skills(u)); set_level(u, SK_ENTERTAINMENT, 1); CuAssertIntEquals(tc, false, has_limited_skills(u)); @@ -372,7 +384,7 @@ static void test_limited_skills(CuTest *tc) { CuAssertIntEquals(tc, true, has_limited_skills(u)); u->skills->id = SK_TAXING; CuAssertIntEquals(tc, false, has_limited_skills(u)); - test_cleanup(); + test_teardown(); } static void test_unit_description(CuTest *tc) { @@ -383,11 +395,11 @@ static void test_unit_description(CuTest *tc) { test_setup(); lang = test_create_locale(); rc = test_create_race("hodor"); - u = test_create_unit(test_create_faction(rc), test_create_region(0,0,0)); + u = test_create_unit(test_create_faction(rc), test_create_region(0, 0, NULL)); CuAssertPtrEquals(tc, 0, u->display); CuAssertStrEquals(tc, 0, u_description(u, lang)); - u->display = strdup("Hodor"); + u->display = str_strdup("Hodor"); CuAssertStrEquals(tc, "Hodor", u_description(u, NULL)); CuAssertStrEquals(tc, "Hodor", u_description(u, lang)); @@ -396,7 +408,7 @@ static void test_unit_description(CuTest *tc) { locale_setstring(lang, "describe_hodor", "HODOR"); CuAssertStrEquals(tc, "HODOR", u_description(u, lang)); - test_cleanup(); + test_teardown(); } static void test_remove_unit(CuTest *tc) { @@ -409,8 +421,8 @@ static void test_remove_unit(CuTest *tc) { test_setup(); init_resources(); rtype = get_resourcetype(R_SILVER); - r = test_create_region(0, 0, 0); - f = test_create_faction(0); + r = test_create_region(0, 0, NULL); + f = test_create_faction(NULL); u2 = test_create_unit(f, r); u1 = test_create_unit(f, r); CuAssertPtrEquals(tc, u1, f->units); @@ -447,20 +459,21 @@ static void test_remove_unit(CuTest *tc) { /* there are now no more units: */ CuAssertPtrEquals(tc, 0, r->units); CuAssertPtrEquals(tc, 0, f->units); - test_cleanup(); + test_teardown(); } static void test_renumber_unit(CuTest *tc) { unit *u1, *u2; + test_setup(); - u1 = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + u1 = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); u2 = test_create_unit(u1->faction, u1->region); rng_init(0); renumber_unit(u1, 0); rng_init(0); renumber_unit(u2, 0); CuAssertTrue(tc, u1->no != u2->no); - test_cleanup(); + test_teardown(); } static void gen_name(unit *u) @@ -474,11 +487,11 @@ static void test_name_unit(CuTest *tc) { test_setup(); rc = test_create_race("skeleton"); - u = test_create_unit(test_create_faction(rc), test_create_region(0, 0, 0)); + u = test_create_unit(test_create_faction(rc), test_create_region(0, 0, NULL)); rc->name_unit = gen_name; name_unit(u); CuAssertStrEquals(tc, "Hodor", unit_getname(u)); - test_cleanup(); + test_teardown(); } static void test_heal_factor(CuTest *tc) { @@ -504,7 +517,7 @@ static void test_heal_factor(CuTest *tc) { CuAssertDblEquals(tc, 1.0, u_heal_factor(u), 0.0); config_set("healing.forest", "1.5"); CuAssertDblEquals(tc, 1.5, u_heal_factor(u), 0.0); - test_cleanup(); + test_teardown(); } static void test_unlimited_units(CuTest *tc) { @@ -541,7 +554,7 @@ static void test_unlimited_units(CuTest *tc) { remove_unit(&u->region->units, u); CuAssertIntEquals(tc, 0, f->num_units); CuAssertIntEquals(tc, 0, f->num_people); - test_cleanup(); + test_teardown(); } static void test_clone_men_bug_2386(CuTest *tc) { @@ -560,13 +573,14 @@ static void test_clone_men_bug_2386(CuTest *tc) { clone_men(u1, u2, 8100); CuAssertIntEquals(tc, 8100, u2->number); CuAssertIntEquals(tc, u2->number * 39, u2->hp); - test_cleanup(); + test_teardown(); } static void test_clone_men(CuTest *tc) { unit *u1, *u2; region *r; faction *f; + test_setup(); r = test_create_region(0, 0, NULL); f = test_create_faction(NULL); @@ -583,13 +597,14 @@ static void test_clone_men(CuTest *tc) { CuAssertIntEquals(tc, 200, u1->hp); CuAssertIntEquals(tc, 1, u2->number); CuAssertIntEquals(tc, 20, u2->hp); - test_cleanup(); + test_teardown(); } static void test_transfermen(CuTest *tc) { unit *u1, *u2; region *r; faction *f; + test_setup(); r = test_create_region(0, 0, NULL); f = test_create_faction(NULL); @@ -604,7 +619,7 @@ static void test_transfermen(CuTest *tc) { CuAssertIntEquals(tc, 140000, u2->hp); CuAssertIntEquals(tc, 0, u1->number); CuAssertIntEquals(tc, 0, u1->hp); - test_cleanup(); + test_teardown(); } CuSuite *get_unit_suite(void) @@ -618,6 +633,8 @@ CuSuite *get_unit_suite(void) SUITE_ADD_TEST(suite, test_clone_men); SUITE_ADD_TEST(suite, test_clone_men_bug_2386); SUITE_ADD_TEST(suite, test_transfermen); + SUITE_ADD_TEST(suite, test_clone_men_bug_2386); + SUITE_ADD_TEST(suite, test_transfermen); SUITE_ADD_TEST(suite, test_remove_unit); SUITE_ADD_TEST(suite, test_remove_empty_units); SUITE_ADD_TEST(suite, test_remove_units_without_faction); diff --git a/src/kernel/version.c b/src/kernel/version.c index 65cbeb110..7c5c2435f 100644 --- a/src/kernel/version.c +++ b/src/kernel/version.c @@ -1,11 +1,13 @@ +#ifdef _MSC_VER #include +#endif #include "version.h" #include #ifndef ERESSEA_VERSION /* the version number, if it was not passed to make with -D */ -#define ERESSEA_VERSION "3.14.0" +#define ERESSEA_VERSION "3.15.0" #endif const char *eressea_version(void) { @@ -18,6 +20,6 @@ const char *eressea_version(void) { int version_no(const char *str) { int maj = 0, min = 0, pat = 0; - sscanf(str, "%d.%d.%d", &maj, &min, &pat); + sscanf(str, "%4d.%4d.%4d", &maj, &min, &pat); return (maj << 16) | (min << 8) | pat; } diff --git a/src/keyword.c b/src/keyword.c index a38c91e07..7519b6449 100644 --- a/src/keyword.c +++ b/src/keyword.c @@ -2,10 +2,10 @@ #include #include "keyword.h" -#include #include #include #include +#include #include @@ -21,7 +21,7 @@ const char * keyword(keyword_t kwd) if (!result[0]) { strcpy(result, "keyword::"); } - strlcpy(result + 9, keywords[kwd], sizeof(result) - 9); + str_strlcpy(result + 9, keywords[kwd], sizeof(result) - 9); return result; } diff --git a/src/keyword.h b/src/keyword.h index 9be7f9f4e..ebdd4d5e7 100644 --- a/src/keyword.h +++ b/src/keyword.h @@ -87,5 +87,6 @@ extern "C" const char *keyword(keyword_t kwd); #ifdef __cplusplus +} #endif #endif diff --git a/src/keyword.test.c b/src/keyword.test.c index 75c31904a..f87992bda 100644 --- a/src/keyword.test.c +++ b/src/keyword.test.c @@ -13,21 +13,23 @@ static void test_init_keywords(CuTest *tc) { test_setup(); lang = get_or_create_locale("en"); + locale_setstring(lang, "keyword::move", "MOVE"); init_keywords(lang); CuAssertIntEquals(tc, K_MOVE, get_keyword("move", lang)); CuAssertStrEquals(tc, "keyword::move", keyword(K_MOVE)); CuAssertPtrEquals(tc, NULL, (void *)keyword(NOKEYWORD)); - test_cleanup(); + test_teardown(); } static void test_infinitive(CuTest *tc) { char buffer[32]; struct locale *lang; struct order *ord; - test_cleanup(); + test_setup(); lang = get_or_create_locale("de"); + locale_setstring(lang, "keyword::study", "LERNE"); init_keyword(lang, K_STUDY, "LERNE"); init_keyword(lang, K_STUDY, "LERNEN"); @@ -36,14 +38,15 @@ static void test_infinitive(CuTest *tc) { CuAssertIntEquals(tc, K_STUDY, get_keyword("LERNEN", lang)); ord = create_order(K_STUDY, lang, ""); - CuAssertStrEquals(tc, "LERNE", get_command(ord, buffer, sizeof(buffer))); + CuAssertStrEquals(tc, "LERNE", get_command(ord, lang, buffer, sizeof(buffer))); free_order(ord); - test_cleanup(); + test_teardown(); } static void test_init_keyword(CuTest *tc) { struct locale *lang; - test_cleanup(); + + test_setup(); lang = get_or_create_locale("de"); init_keyword(lang, K_MOVE, "NACH"); @@ -55,23 +58,23 @@ static void test_init_keyword(CuTest *tc) { CuAssertIntEquals(tc, K_STUDY, get_keyword("lerne", lang)); CuAssertIntEquals(tc, K_DESTROY, get_keyword("zerst\xC3\xB6ren", lang)); CuAssertIntEquals(tc, NOKEYWORD, get_keyword("potato", lang)); - test_cleanup(); + test_teardown(); } static void test_findkeyword(CuTest *tc) { - test_cleanup(); + test_setup(); CuAssertIntEquals(tc, K_MOVE, findkeyword("move")); CuAssertIntEquals(tc, K_STUDY, findkeyword("study")); CuAssertIntEquals(tc, NOKEYWORD, findkeyword("")); CuAssertIntEquals(tc, NOKEYWORD, findkeyword("potato")); - test_cleanup(); + test_teardown(); } static void test_get_shortest_match(CuTest *tc) { struct locale *lang; critbit_tree ** cb; - test_cleanup(); + test_setup(); lang = get_or_create_locale("en"); cb = (critbit_tree **)get_translations(lang, UT_KEYWORDS); @@ -83,7 +86,7 @@ static void test_get_shortest_match(CuTest *tc) { CuAssertIntEquals(tc, K_STATUS, get_keyword("COM", lang)); CuAssertIntEquals(tc, K_STATUS, get_keyword("COMBAT", lang)); CuAssertIntEquals(tc, K_COMBATSPELL, get_keyword("COMBATS", lang)); - test_cleanup(); + test_teardown(); } CuSuite *get_keyword_suite(void) diff --git a/src/laws.c b/src/laws.c index 1f3633d14..d90d2f173 100644 --- a/src/laws.c +++ b/src/laws.c @@ -17,7 +17,9 @@ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. **/ +#ifdef _MSC_VER #include +#endif #include #include "laws.h" @@ -41,6 +43,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "teleport.h" #include "calendar.h" #include "guard.h" +#include "volcano.h" /* attributes includes */ #include @@ -72,23 +75,25 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include -#include /* for volcanoes in emigration (needs a flag) */ +#include #include /* util includes */ #include #include -#include #include #include #include #include #include +#include #include #include #include +#include #include #include +#include #include #include @@ -155,6 +160,45 @@ static bool RemoveNMRNewbie(void) return value != 0; } +static void dumbeffect(unit *u) { + int effect = get_effect(u, oldpotiontype[P_FOOL]); + if (effect > 0) { /* Trank "Dumpfbackenbrot" */ + skill *sv = u->skills, *sb = NULL; + while (sv != u->skills + u->skill_size) { + if (sb == NULL || skill_compare(sv, sb) > 0) { + sb = sv; + } + ++sv; + } + /* bestes Talent raussuchen */ + if (sb != NULL) { + int weeks = u->number; + if (weeks > effect) weeks = effect; + reduce_skill(u, sb, weeks); + ADDMSG(&u->faction->msgs, msg_message("dumbeffect", + "unit weeks skill", u, weeks, (skill_t)sb->id)); + } /* sonst Glück gehabt: wer nix weiss, kann nix vergessen... */ + change_effect(u, oldpotiontype[P_FOOL], -effect); + } +} + +static void astral_crumble(unit *u) { + item **itemp = &u->items; + while (*itemp) { + item *itm = *itemp; + if ((itm->type->flags & ITF_NOTLOST) == 0) { + if (itm->type->flags & (ITF_BIG | ITF_ANIMAL | ITF_CURSED)) { + ADDMSG(&u->faction->msgs, msg_message("itemcrumble", + "unit region item amount", + u, u->region, itm->type->rtype, itm->number)); + i_free(i_remove(itemp, itm)); + continue; + } + } + itemp = &itm->next; + } +} + static void age_unit(region * r, unit * u) { const race *rc = u_race(u); @@ -163,21 +207,11 @@ static void age_unit(region * r, unit * u) if (u->number > 0 && rc->age_unit) { rc->age_unit(u); } - if (u->region && is_astral(u->region)) { - item **itemp = &u->items; - while (*itemp) { - item *itm = *itemp; - if ((itm->type->flags & ITF_NOTLOST) == 0) { - if (itm->type->flags & (ITF_BIG | ITF_ANIMAL | ITF_CURSED)) { - ADDMSG(&u->faction->msgs, msg_message("itemcrumble", - "unit region item amount", - u, u->region, itm->type->rtype, itm->number)); - i_free(i_remove(itemp, itm)); - continue; - } - } - itemp = &itm->next; - } + if (u->attribs) { + dumbeffect(u); + } + if (u->items && u->region && is_astral(u->region)) { + astral_crumble(u); } } @@ -192,25 +226,6 @@ static void live(region * r) /* IUW: age_unit() kann u loeschen, u->next ist dann * undefiniert, also muessen wir hier schon das nächste * Element bestimmen */ - - int effect = get_effect(u, oldpotiontype[P_FOOL]); - if (effect > 0) { /* Trank "Dumpfbackenbrot" */ - skill *sv = u->skills, *sb = NULL; - while (sv != u->skills + u->skill_size) { - if (sb == NULL || skill_compare(sv, sb) > 0) { - sb = sv; - } - ++sv; - } - /* bestes Talent raussuchen */ - if (sb != NULL) { - int weeks = MIN(effect, u->number); - reduce_skill(u, sb, weeks); - ADDMSG(&u->faction->msgs, msg_message("dumbeffect", - "unit weeks skill", u, weeks, (skill_t)sb->id)); - } /* sonst Glück gehabt: wer nix weiss, kann nix vergessen... */ - change_effect(u, oldpotiontype[P_FOOL], -effect); - } age_unit(r, u); if (*up == u) up = &u->next; @@ -247,9 +262,19 @@ static void calculate_emigration(region * r) int rp = rpeasants(r); int max_immigrants = MAX_IMMIGRATION(maxp - rp); - if (r->terrain == newterrain(T_VOLCANO) - || r->terrain == newterrain(T_VOLCANO_SMOKING)) { - max_immigrants = max_immigrants / 10; + + if (volcano_module()) { + static int terrain_cache; + static const terrain_type *t_volcano; + static const terrain_type *t_smoking; + + if (terrain_changed(&terrain_cache)) { + t_volcano = newterrain(T_VOLCANO); + t_smoking = newterrain(T_VOLCANO_SMOKING); + } + if (r->terrain == t_volcano || r->terrain == t_smoking) { + max_immigrants = max_immigrants / 10; + } } for (i = 0; max_immigrants > 0 && i != MAXDIRECTIONS; i++) { @@ -262,7 +287,7 @@ static void calculate_emigration(region * r) int max_emigration = MAX_EMIGRATION(rp2 - maxp2); if (max_emigration > 0) { - max_emigration = MIN(max_emigration, max_immigrants); + if (max_emigration > max_immigrants) max_emigration = max_immigrants; r->land->newpeasants += max_emigration; rc->land->newpeasants -= max_emigration; max_immigrants -= max_emigration; @@ -287,8 +312,8 @@ int peasant_luck_effect(int peasants, int luck, int maxp, double variance) int births = 0; double mean; if (luck == 0) return 0; - - mean = peasant_luck_factor() * peasant_growth_factor() * MIN(luck, peasants); + mean = fmin(luck, peasants); + mean *= peasant_luck_factor() * peasant_growth_factor(); mean *= ((peasants / (double)maxp < .9) ? 1 : PEASANTFORCE); births = RAND_ROUND(normalvariate(mean, variance * mean)); @@ -301,11 +326,11 @@ int peasant_luck_effect(int peasants, int luck, int maxp, double variance) static void peasants(region * r, int rule) { - int peasants = rpeasants(r); + int rp = rpeasants(r); int money = rmoney(r); - int maxp = production(r); + int maxp = max_production(r); int n, satiated; - int dead = 0; + int dead = 0, peasants = rp; if (peasants > 0 && rule > 0) { int luck = 0; @@ -325,7 +350,8 @@ static void peasants(region * r, int rule) /* Alle werden satt, oder halt soviele für die es auch Geld gibt */ - satiated = MIN(peasants, money / maintenance_cost(NULL)); + satiated = money / maintenance_cost(NULL); + if (satiated > peasants) satiated = peasants; rsetmoney(r, money - satiated * maintenance_cost(NULL)); /* Von denjenigen, die nicht satt geworden sind, verhungert der @@ -334,7 +360,8 @@ static void peasants(region * r, int rule) /* Es verhungert maximal die unterernährten Bevölkerung. */ - n = MIN(peasants - satiated, rpeasants(r)); + n = peasants - satiated; + if (n > rp) n = rp; dead += (int)(0.5 + n * PEASANT_STARVATION_CHANCE); if (dead > 0) { @@ -415,21 +442,21 @@ static void horses(region * r) /* Logistisches Wachstum, Optimum bei halbem Maximalbesatz. */ maxhorses = region_maxworkers(r) / 10; - maxhorses = MAX(0, maxhorses); horses = rhorses(r); if (horses > 0) { if (is_cursed(r->attribs, &ct_godcursezone)) { rsethorses(r, (int)(horses * 0.9)); } - else if (maxhorses) { - int i; + else if (maxhorses > 0) { double growth = (RESOURCE_QUANTITY * HORSEGROWTH * 200 * (maxhorses - horses)) / maxhorses; if (growth > 0) { - if (a_find(r->attribs, &at_horseluck)) + int i; + if (a_find(r->attribs, &at_horseluck)) { growth *= 2; + } /* printf("Horses: <%d> %d -> ", growth, horses); */ i = (int)(0.5 + (horses * 0.0001) * growth); /* printf("%d\n", horses); */ @@ -449,7 +476,7 @@ static void horses(region * r) if (r2 && fval(r2->terrain, WALK_INTO)) { int pt = (rhorses(r) * HORSEMOVE) / 100; pt = (int)normalvariate(pt, pt / 4.0); - pt = MAX(0, pt); + if (pt < 0) pt = 0; if (fval(r2, RF_MIGRATION)) rsethorses(r2, rhorses(r2) + pt); else { @@ -551,18 +578,19 @@ growing_trees_e3(region * r, const int current_season, static void growing_trees(region * r, const int current_season, const int last_weeks_season) { - int growth, grownup_trees, i, seeds, sprout; - direction_t d; + int grownup_trees, i, seeds, sprout; attrib *a; if (current_season == SEASON_SUMMER || current_season == SEASON_AUTUMN) { double seedchance = 0.01F * RESOURCE_QUANTITY; - int elves = count_race(r, get_race(RC_ELF)); + int mp, elves = count_race(r, get_race(RC_ELF)); + direction_t d; a = a_find(r->attribs, &at_germs); if (a && last_weeks_season == SEASON_SPRING) { /* ungekeimte Samen bleiben erhalten, Sprößlinge wachsen */ - sprout = MIN(a->data.sa[1], rtrees(r, 1)); + sprout = rtrees(r, 1); + if (sprout > a->data.sa[1]) sprout = a->data.sa[1]; /* aus dem gesamt Sprößlingepool abziehen */ rsettrees(r, 1, rtrees(r, 1) - sprout); /* zu den Bäumen hinzufügen */ @@ -577,12 +605,14 @@ growing_trees(region * r, const int current_season, const int last_weeks_season) return; } - if (production(r) <= 0) + mp = max_production(r); + if (mp <= 0) return; /* Grundchance 1.0% */ /* Jeder Elf in der Region erhöht die Chance marginal */ - elves = MIN(elves, production(r) / 8); + mp = mp / 8; + if (elves > mp) elves = mp; if (elves) { seedchance += 1.0 - pow(0.99999, elves * RESOURCE_QUANTITY); } @@ -627,6 +657,7 @@ growing_trees(region * r, const int current_season, const int last_weeks_season) } else if (current_season == SEASON_SPRING) { + int growth; if (is_cursed(r->attribs, &ct_godcursezone)) return; @@ -648,7 +679,8 @@ growing_trees(region * r, const int current_season, const int last_weeks_season) /* Raubbau abfangen, es dürfen nie mehr Samen wachsen, als aktuell * in der Region sind */ - seeds = MIN(a->data.sa[0], rtrees(r, 0)); + seeds = rtrees(r, 0); + if (seeds > a->data.sa[0]) seeds = a->data.sa[0]; sprout = 0; for (i = 0; i < seeds; i++) { @@ -668,7 +700,8 @@ growing_trees(region * r, const int current_season, const int last_weeks_season) * der Region entfernt werden können, da Jungbäume in der gleichen * Runde nachwachsen, wir also nicht mehr zwischen diesjährigen und * 'alten' Jungbäumen unterscheiden könnten */ - sprout = MIN(a->data.sa[1], rtrees(r, 1)); + sprout = rtrees(r, 1); + if (sprout > a->data.sa[1]) sprout = a->data.sa[1]; grownup_trees = 0; for (i = 0; i < sprout; i++) { @@ -691,6 +724,7 @@ growing_herbs(region * r, const int current_season, const int last_weeks_season) * * Jedes Kraut hat eine Wahrscheinlichkeit von (100-(vorhandene * Kräuter))% sich zu vermehren. */ + UNUSED_ARG(last_weeks_season); if (current_season != SEASON_WINTER) { int i; for (i = rherbs(r); i > 0; i--) { @@ -708,7 +742,9 @@ void immigration(void) for (r = regions; r; r = r->next) { if (r->land && r->land->newpeasants) { int rp = rpeasants(r) + r->land->newpeasants; - rsetpeasants(r, MAX(0, rp)); + /* FIXME: kann ernsthaft abs(newpeasants) > rpeasants(r) sein? */ + if (rp < 0) rp = 0; + rsetpeasants(r, rp); } /* Genereate some (0-6 depending on the income) peasants out of nothing */ /* if less than 50 are in the region and there is space and no monster or demon units in the region */ @@ -814,7 +850,7 @@ void demographics(void) peasants(r, peasant_rules); if (r->age > 20) { - double mwp = MAX(region_maxworkers(r), 1); + double mwp = fmax(region_maxworkers(r), 1); double prob = pow(rpeasants(r) / (mwp * wage(r, NULL, NULL, turn) * 0.13), 4.0) * PLAGUE_CHANCE; @@ -889,7 +925,7 @@ static int slipthru(const region * r, const unit * u, const building * b) int can_contact(const region * r, const unit * u, const unit * u2) { /* hier geht es nur um die belagerung von burgen */ - + UNUSED_ARG(r); if (u->building == u2->building) { return 1; } @@ -910,7 +946,7 @@ int contact_cmd(unit * u, order * ord) unit *u2; int n; - init_order(ord); + init_order_depr(ord); n = read_unitid(u->faction, u->region); u2 = findunit(n); @@ -960,7 +996,7 @@ int quit_cmd(unit * u, struct order *ord) const char *passwd; keyword_t kwd; - kwd = init_order(ord); + kwd = init_order_depr(ord); assert(kwd == K_QUIT); passwd = gettoken(token, sizeof(token)); if (checkpasswd(f, (const char *)passwd)) { @@ -968,7 +1004,7 @@ int quit_cmd(unit * u, struct order *ord) } else { char buffer[64]; - write_order(ord, buffer, sizeof(buffer)); + write_order(ord, f->locale, buffer, sizeof(buffer)); cmistake(u, ord, 86, MSG_EVENT); log_warning("QUIT with illegal password for faction %s: %s\n", itoa36(f->no), buffer); } @@ -978,6 +1014,7 @@ int quit_cmd(unit * u, struct order *ord) static bool mayenter(region * r, unit * u, building * b) { unit *u2; + UNUSED_ARG(r); if (fval(b, BLD_UNGUARDED)) return true; u2 = building_owner(b); @@ -1146,7 +1183,7 @@ void do_enter(struct region *r, bool is_final_attempt) unit *ulast = NULL; const char * s; - init_order(ord); + init_order_depr(ord); s = gettoken(token, sizeof(token)); p = findparam_ex(s, u->faction->locale); id = getid(); @@ -1229,7 +1266,7 @@ static void nmr_death(faction * f) static void remove_idle_players(void) { faction **fp; - int timeout = NMRTimeout(); + int i, timeout = NMRTimeout(); log_info(" - beseitige Spieler, die sich zu lange nicht mehr gemeldet haben..."); @@ -1253,7 +1290,9 @@ static void remove_idle_players(void) } log_info(" - beseitige Spieler, die sich nach der Anmeldung nicht gemeldet haben..."); - age = calloc(MAX(4, turn + 1), sizeof(int)); + i = turn + 1; + if (i < 4) i = 4; + age = calloc(i, sizeof(int)); for (fp = &factions; *fp;) { faction *f = *fp; if (!is_monsters(f)) { @@ -1283,10 +1322,6 @@ void quit(void) } else { ++f->age; - if (f->age + 1 < NewbieImmunity()) { - ADDMSG(&f->msgs, msg_message("newbieimmunity", "turns", - NewbieImmunity() - f->age - 1)); - } fptr = &f->next; } } @@ -1306,7 +1341,7 @@ int ally_cmd(unit * u, struct order *ord) int keyword, not_kw; const char *s; - init_order(ord); + init_order_depr(ord); f = getfaction(); if (f == NULL || is_monsters(f)) { @@ -1473,7 +1508,7 @@ int prefix_cmd(unit * u, struct order *ord) for (in = pnames; in->lang != lang; in = in->next); } - init_order(ord); + init_order_depr(ord); s = gettoken(token, sizeof(token)); if (!s || !*s) { @@ -1517,7 +1552,7 @@ int display_cmd(unit * u, struct order *ord) const char *str; region *r = u->region; - init_order(ord); + init_order_depr(ord); str = gettoken(token, sizeof(token)); switch (findparam_ex(str, u->faction->locale)) { @@ -1576,17 +1611,17 @@ int display_cmd(unit * u, struct order *ord) free(*s); if (s2) { - char * str = strdup(s2); - if (unicode_utf8_trim(str) != 0) { + char * sdup = str_strdup(s2); + if (unicode_utf8_trim(sdup) != 0) { log_info("trimming info: %s", s2); } - if (strlen(str) >= DISPLAYSIZE) { - str[DISPLAYSIZE-1] = 0; + if (strlen(sdup) >= DISPLAYSIZE) { + sdup[DISPLAYSIZE-1] = 0; } - *s = str; + *s = sdup; } else { - *s = 0; + *s = NULL; } } @@ -1620,13 +1655,13 @@ static int rename_cmd(unit * u, order * ord, char **s, const char *s2) /* TODO: Validate to make sure people don't have illegal characters in * names, phishing-style? () come to mind. */ - strlcpy(name, s2, sizeof(name)); + str_strlcpy(name, s2, sizeof(name)); if (unicode_utf8_trim(name) != 0) { log_info("trimming name: %s", s2); } free(*s); - *s = strdup(name); + *s = str_strdup(name); return 0; } @@ -1690,7 +1725,7 @@ int name_cmd(struct unit *u, struct order *ord) bool foreign = false; const char *str; - init_order(ord); + init_order_depr(ord); str = gettoken(token, sizeof(token)); p = findparam_ex(str, u->faction->locale); @@ -1806,11 +1841,13 @@ int name_cmd(struct unit *u, struct order *ord) s = &sh->name; } else { + unit *uo; if (!u->ship) { cmistake(u, ord, 144, MSG_PRODUCE); break; } - if (ship_owner(u->ship) != u) { + uo = ship_owner(u->ship); + if (uo->faction != u->faction) { cmistake(u, ord, 12, MSG_PRODUCE); break; } @@ -1948,7 +1985,7 @@ int mail_cmd(unit * u, struct order *ord) const char *s; int n, cont; - init_order(ord); + init_order_depr(ord); s = gettoken(token, sizeof(token)); /* Falls kein Parameter, ist das eine Einheitsnummer; @@ -2105,9 +2142,9 @@ int banner_cmd(unit * u, struct order *ord) const char * s; free(u->faction->banner); - init_order(ord); + init_order_depr(ord); s = getstrtoken(); - u->faction->banner = s ? strdup(s) : 0; + u->faction->banner = s ? str_strdup(s) : 0; add_message(&u->faction->msgs, msg_message("changebanner", "value", u->faction->banner)); @@ -2118,7 +2155,7 @@ int email_cmd(unit * u, struct order *ord) { const char *s; - init_order(ord); + init_order_depr(ord); s = getstrtoken(); if (!s || !s[0]) { @@ -2126,13 +2163,13 @@ int email_cmd(unit * u, struct order *ord) } else { faction *f = u->faction; - if (set_email(&f->email, s) != 0) { + if (check_email(s) == 0) { + faction_setemail(f, s); + ADDMSG(&f->msgs, msg_message("changemail", "value", faction_getemail(f))); + } else { log_error("Invalid email address for faction %s: %s\n", itoa36(f->no), s); ADDMSG(&f->msgs, msg_message("changemail_invalid", "value", s)); } - else { - ADDMSG(&f->msgs, msg_message("changemail", "value", f->email)); - } } return 0; } @@ -2140,14 +2177,14 @@ int email_cmd(unit * u, struct order *ord) int password_cmd(unit * u, struct order *ord) { char pwbuf[32]; - int i; const char *s; bool pwok = true; - init_order(ord); + init_order_depr(ord); s = gettoken(pwbuf, sizeof(pwbuf)); if (!s || !*s) { + int i; for (i = 0; i < 6; i++) pwbuf[i] = (char)(97 + rng_int() % 26); pwbuf[6] = 0; @@ -2162,7 +2199,7 @@ int password_cmd(unit * u, struct order *ord) } if (!pwok) { cmistake(u, ord, 283, MSG_EVENT); - strlcpy(pwbuf, itoa36(rng_int()), sizeof(pwbuf)); + str_strlcpy(pwbuf, itoa36(rng_int()), sizeof(pwbuf)); } faction_setpassword(u->faction, password_encode(pwbuf, PASSWORD_DEFAULT)); ADDMSG(&u->faction->msgs, msg_message("changepasswd", @@ -2177,7 +2214,7 @@ int send_cmd(unit * u, struct order *ord) const char *s; int option; - init_order(ord); + init_order_depr(ord); s = gettoken(token, sizeof(token)); option = findoption(s, u->faction->locale); @@ -2205,6 +2242,10 @@ int send_cmd(unit * u, struct order *ord) return 0; } +static void display_potion(unit * u, const item_type * itype) { + show_item(u, itype); +} + static void display_item(unit * u, const item_type * itype) { faction * f = u->faction; @@ -2223,160 +2264,11 @@ static void display_item(unit * u, const item_type * itype) itype->weight, itype->rtype, info)); } -static void display_potion(unit * u, const potion_type * ptype) +static void display_race(faction * f, const race * rc) { - faction * f = u->faction; - attrib *a; + char buf[2048]; - a = a_find(f->attribs, &at_showitem); - while (a && a->data.v != ptype) - a = a->next; - if (!a) { - a = a_add(&f->attribs, a_new(&at_showitem)); - a->data.v = (void *)ptype->itype; - } -} - -static void display_race(unit * u, const race * rc) -{ - faction * f = u->faction; - const char *name, *key; - const char *info; - int a, at_count; - char buf[2048], *bufp = buf; - size_t size = sizeof(buf) - 1; - size_t bytes; - - name = rc_name_s(rc, NAME_SINGULAR); - - bytes = slprintf(bufp, size, "%s: ", LOC(f->locale, name)); - assert(bytes <= INT_MAX); - if (wrptr(&bufp, &size, (int)bytes) != 0) - WARN_STATIC_BUFFER(); - - key = mkname("raceinfo", rc->_name); - info = locale_getstring(f->locale, key); - if (info == NULL) { - info = LOC(f->locale, mkname("raceinfo", "no_info")); - } - - if (info) bufp = STRLCPY(bufp, info, size); - - /* hp_p : Trefferpunkte */ - bytes = - slprintf(bufp, size, " %d %s", rc->hitpoints, LOC(f->locale, - "stat_hitpoints")); - assert(bytes <= INT_MAX); - if (wrptr(&bufp, &size, (int)bytes) != 0) - WARN_STATIC_BUFFER(); - - /* b_attacke : Angriff */ - bytes = - slprintf(bufp, size, ", %s: %d", LOC(f->locale, "stat_attack"), - (rc->at_default + rc->at_bonus)); - assert(bytes <= INT_MAX); - if (wrptr(&bufp, &size, (int)bytes) != 0) - WARN_STATIC_BUFFER(); - - /* b_defense : Verteidigung */ - bytes = - slprintf(bufp, size, ", %s: %d", LOC(f->locale, "stat_defense"), - (rc->df_default + rc->df_bonus)); - assert(bytes <= INT_MAX); - if (wrptr(&bufp, &size, (int)bytes) != 0) - WARN_STATIC_BUFFER(); - - /* b_armor : Rüstung */ - if (rc->armor > 0) { - bytes = - slprintf(bufp, size, ", %s: %d", LOC(f->locale, "stat_armor"), rc->armor); - assert(bytes <= INT_MAX); - if (wrptr(&bufp, &size, (int)bytes) != 0) - WARN_STATIC_BUFFER(); - } - - if (size > 1) { - *bufp++ = '.'; - --size; - } - else - WARN_STATIC_BUFFER(); - - /* b_damage : Schaden */ - at_count = 0; - for (a = 0; a < RACE_ATTACKS; a++) { - if (rc->attack[a].type != AT_NONE) { - at_count++; - } - } - if (rc->battle_flags & BF_EQUIPMENT) { - if (wrptr(&bufp, &size, snprintf(bufp, size, " %s", LOC(f->locale, "stat_equipment"))) != 0) - WARN_STATIC_BUFFER(); - } - if (rc->battle_flags & BF_RES_PIERCE) { - if (wrptr(&bufp, &size, snprintf(bufp, size, " %s", LOC(f->locale, "stat_pierce"))) != 0) - WARN_STATIC_BUFFER(); - } - if (rc->battle_flags & BF_RES_CUT) { - if (wrptr(&bufp, &size, snprintf(bufp, size, " %s", LOC(f->locale, "stat_cut"))) != 0) - WARN_STATIC_BUFFER(); - } - if (rc->battle_flags & BF_RES_BASH) { - if (wrptr(&bufp, &size, snprintf(bufp, size, " %s", LOC(f->locale, "stat_bash"))) != 0) - WARN_STATIC_BUFFER(); - } - - if (wrptr(&bufp, &size, snprintf(bufp, size, " %d %s", at_count, LOC(f->locale, (at_count == 1) ? "stat_attack" : "stat_attacks"))) != 0) - WARN_STATIC_BUFFER(); - - for (a = 0; a < RACE_ATTACKS; a++) { - if (rc->attack[a].type != AT_NONE) { - if (a != 0) - bufp = STRLCPY(bufp, ", ", size); - else - bufp = STRLCPY(bufp, ": ", size); - - switch (rc->attack[a].type) { - case AT_STANDARD: - bytes = - (size_t)snprintf(bufp, size, "%s (%s)", - LOC(f->locale, "attack_standard"), rc->def_damage); - break; - case AT_NATURAL: - bytes = - (size_t)snprintf(bufp, size, "%s (%s)", - LOC(f->locale, "attack_natural"), rc->attack[a].data.dice); - break; - case AT_SPELL: - case AT_COMBATSPELL: - case AT_DRAIN_ST: - case AT_DRAIN_EXP: - case AT_DAZZLE: - bytes = (size_t)snprintf(bufp, size, "%s", LOC(f->locale, "attack_magical")); - break; - case AT_STRUCTURAL: - bytes = - (size_t)snprintf(bufp, size, "%s (%s)", - LOC(f->locale, "attack_structural"), rc->attack[a].data.dice); - break; - default: - bytes = 0; - } - - assert(bytes <= INT_MAX); - if (bytes && wrptr(&bufp, &size, (int)bytes) != 0) - WARN_STATIC_BUFFER(); - } - } - - if (size > 1) { - *bufp++ = '.'; - --size; - } - else - WARN_STATIC_BUFFER(); - - *bufp = 0; + report_raceinfo(rc, f->locale, buf, sizeof(buf)); addmessage(0, f, buf, MSG_EVENT, ML_IMPORTANT); } @@ -2395,31 +2287,22 @@ static void reshow_other(unit * u, struct order *ord, const char *s) { if (itype) { /* if this is a potion, we need the right alchemy skill */ - int i = i_get(u->items, itype); - err = 36; /* we do not have this item? */ - if (i <= 0) { - /* we don't have the item, but it may be a potion that we know */ - const potion_type *ptype = resource2potion(item2resource(itype)); - if (ptype) { - if (2 * ptype->level > effskill(u, SK_ALCHEMY, 0)) { - itype = NULL; - } - } else { - itype = NULL; + if (itype->flags & ITF_POTION) { + /* we don't have the item, but it is a potion. do we know it? */ + int level = potion_level(itype); + if (level > 0 && 2 * level <= effskill(u, SK_ALCHEMY, 0)) { + display_potion(u, itype); + found = true; } } - } - - if (itype) { - const potion_type *ptype = itype->rtype->ptype; - if (ptype) { - display_potion(u, ptype); - } else { - display_item(u, itype); + int i = i_get(u->items, itype); + if (i > 0) { + found = true; + display_item(u, itype); + } } - found = true; } if (sp) { @@ -2434,34 +2317,25 @@ static void reshow_other(unit * u, struct order *ord, const char *s) { } if (rc && u_race(u) == rc) { - display_race(u, rc); + display_race(u->faction, rc); found = true; } } - if (!found) - cmistake(u, ord, err, MSG_EVENT); + if (!found) { + cmistake(u, ord, err, MSG_EVENT); + } } static void reshow(unit * u, struct order *ord, const char *s, param_t p) { - int skill, c; - const potion_type *ptype; - switch (p) { case P_ZAUBER: a_removeall(&u->faction->attribs, &at_seenspell); break; case P_POTIONS: - skill = effskill(u, SK_ALCHEMY, 0); - c = 0; - for (ptype = potiontypes; ptype != NULL; ptype = ptype->next) { - if (ptype->level * 2 <= skill) { - display_potion(u, ptype); - ++c; - } - } - if (c == 0) + if (!display_potions(u)) { cmistake(u, ord, 285, MSG_EVENT); + } break; case NOPARAM: reshow_other(u, ord, s); @@ -2512,7 +2386,7 @@ int group_cmd(unit * u, struct order *ord) { keyword_t kwd; - kwd = init_order(ord); + kwd = init_order_depr(ord); assert(kwd == K_GROUP); join_group(u, getstrtoken()); return 0; @@ -2520,12 +2394,12 @@ int group_cmd(unit * u, struct order *ord) int origin_cmd(unit * u, struct order *ord) { - short px, py; + int px, py; - init_order(ord); + init_order_depr(ord); - px = (short)getint(); - py = (short)getint(); + px = getint(); + py = getint(); faction_setorigin(u->faction, getplaneid(u->region), px, py); return 0; @@ -2534,7 +2408,7 @@ int origin_cmd(unit * u, struct order *ord) int guard_off_cmd(unit * u, struct order *ord) { assert(getkeyword(ord) == K_GUARD); - init_order(ord); + init_order_depr(ord); if (getparam(u->faction->locale) == P_NOT) { setguard(u, false); @@ -2548,7 +2422,7 @@ int reshow_cmd(unit * u, struct order *ord) const char *s; param_t p = NOPARAM; - init_order(ord); + init_order_depr(ord); s = gettoken(lbuf, sizeof(lbuf)); if (s && isparam(s, u->faction->locale, P_ANY)) { @@ -2565,7 +2439,7 @@ int status_cmd(unit * u, struct order *ord) char token[128]; const char *s; - init_order(ord); + init_order_depr(ord); s = gettoken(token, sizeof(token)); switch (findparam(s, u->faction->locale)) { case P_NOT: @@ -2613,7 +2487,7 @@ int combatspell_cmd(unit * u, struct order *ord) int level = 0; spell *sp = 0; - init_order(ord); + init_order_depr(ord); s = gettoken(token, sizeof(token)); /* KAMPFZAUBER [NICHT] löscht alle gesetzten Kampfzauber */ @@ -2625,8 +2499,7 @@ int combatspell_cmd(unit * u, struct order *ord) /* Optional: STUFE n */ if (findparam(s, u->faction->locale) == P_LEVEL) { /* Merken, setzen kommt erst später */ - level = getint(); - level = MAX(0, level); + level = getuint(); s = gettoken(token, sizeof(token)); } @@ -2658,7 +2531,7 @@ int guard_on_cmd(unit * u, struct order *ord) assert(u); assert(u->faction); - init_order(ord); + init_order_depr(ord); /* GUARD NOT is handled in goard_off_cmd earlier in the turn */ if (getparam(u->faction->locale) == P_NOT) { @@ -2739,7 +2612,7 @@ void restack_units(void) int id; unit *v; - init_order(ord); + init_order_depr(ord); s = gettoken(token, sizeof(token)); p = findparam(s, u->faction->locale); id = getid(); @@ -2853,16 +2726,20 @@ static void age_stonecircle(building *b) { if (!c) { int sk = effskill(mage, SK_MAGIC, 0); float effect = 100; - /* the mage reactivates the circle */ - c = create_curse(mage, &rt->attribs, &ct_astralblock, - (float)MAX(1, sk), MAX(1, sk / 2), effect, 0); - ADDMSG(&r->msgs, - msg_message("astralshield_activate", "region unit", r, mage)); + if (sk > 0) { + int vig = sk; + int dur = (sk + 1) / 2; + /* the mage reactivates the circle */ + c = create_curse(mage, &rt->attribs, &ct_astralblock, + vig, dur, effect, 0); + ADDMSG(&r->msgs, + msg_message("astralshield_activate", "region unit", r, mage)); + } } else { int sk = effskill(mage, SK_MAGIC, 0); - c->duration = MAX(c->duration, sk / 2); - c->vigour = MAX(c->vigour, (float)sk); + if (c->duration < sk / 2) c->duration = sk / 2; + if (c->vigour < sk) c->vigour = sk; } } } @@ -2903,12 +2780,14 @@ static void ageing(void) /* Goliathwasser */ int i = get_effect(u, oldpotiontype[P_STRONG]); if (i > 0) { - change_effect(u, oldpotiontype[P_STRONG], -1 * MIN(u->number, i)); + if (i > u->number) i = u->number; + change_effect(u, oldpotiontype[P_STRONG], - i); } /* Berserkerblut */ i = get_effect(u, oldpotiontype[P_BERSERK]); if (i > 0) { - change_effect(u, oldpotiontype[P_BERSERK], -1 * MIN(u->number, i)); + if (i > u->number) i = u->number; + change_effect(u, oldpotiontype[P_BERSERK], - i); } if (u->attribs) { @@ -2978,13 +2857,14 @@ static int maxunits(const faction * f) { int flimit = rule_faction_limit(); int alimit = rule_alliance_limit(); + UNUSED_ARG(f); if (alimit == 0) { return flimit; } if (flimit == 0) { return alimit; } - return MIN(alimit, flimit); + return (alimit > flimit) ? flimit : alimit; } int checkunitnumber(const faction * f, int add) @@ -3049,7 +2929,7 @@ void maketemp_cmd(unit *u, order **olist) unit *u2; order **ordp, **oinsert; #ifndef NDEBUG - keyword_t kwd = init_order(makeord); + keyword_t kwd = init_order_depr(makeord); assert(kwd == K_MAKETEMP); #endif alias = getid(); @@ -3292,7 +3172,7 @@ void monthly_healing(void) p *= u_heal_factor(u); if (u->hp < umhp) { - double maxheal = MAX(u->number, umhp / 20.0); + double maxheal = fmax(u->number, umhp / 20.0); int addhp; if (active_building(u, bt_find("inn"))) { p *= 1.5; @@ -3307,7 +3187,8 @@ void monthly_healing(void) ++addhp; /* Aufaddieren der geheilten HP. */ - u->hp = MIN(u->hp + addhp, umhp); + if (umhp > u->hp + addhp) umhp = u->hp + addhp; + u->hp = umhp; /* soll man an negativer regeneration sterben können? */ assert(u->hp > 0); @@ -3347,7 +3228,7 @@ void defaultorders(void) char lbuf[8192]; order *new_order = 0; const char *s; - init_order(ord); + init_order_depr(ord); s = gettoken(lbuf, sizeof(lbuf)); if (s) { new_order = parse_order(s, u->faction->locale); @@ -3463,7 +3344,7 @@ int use_cmd(unit * u, struct order *ord) int n, err = ENOITEM; const item_type *itype; - init_order(ord); + init_order_depr(ord); t = gettoken(token, sizeof(token)); if (!t) { @@ -3518,7 +3399,7 @@ int pay_cmd(unit * u, struct order *ord) param_t p; int id; - init_order(ord); + init_order_depr(ord); p = getparam(u->faction->locale); id = getid(); if (p == P_NOT) { @@ -3572,7 +3453,7 @@ static int reserve_i(unit * u, struct order *ord, int flags) const item_type *itype; const char *s; - init_order(ord); + init_order_depr(ord); s = gettoken(token, sizeof(token)); count = s ? atoip(s) : 0; para = findparam(s, u->faction->locale); @@ -3615,7 +3496,7 @@ int claim_cmd(unit * u, struct order *ord) int n = 1; const item_type *itype = 0; - init_order(ord); + init_order_depr(ord); t = gettoken(token, sizeof(token)); if (t) { @@ -3633,7 +3514,7 @@ int claim_cmd(unit * u, struct order *ord) if (itype) { item **iclaim = i_find(&u->faction->items, itype); if (iclaim && *iclaim) { - n = MIN(n, (*iclaim)->number); + if (n > (*iclaim)->number) n = (*iclaim)->number; i_change(iclaim, itype, -n); i_change(&u->items, itype, n); } @@ -3888,13 +3769,12 @@ int armedmen(const unit * u, bool siege_weapons) const weapon_type *wtype = resource2weapon(itm->type->rtype); if (wtype == NULL || (!siege_weapons && (wtype->flags & WTF_SIEGE))) continue; - if (effskill(u, wtype->skill, 0) >= wtype->minskill) + if (effskill(u, wtype->skill, 0) >= 1) n += itm->number; - /* if (effskill(u, wtype->skill) >= wtype->minskill) n += itm->number; */ if (n >= u->number) break; } - n = MIN(n, u->number); + if (n > u->number) n = u->number; } } return n; @@ -3909,7 +3789,7 @@ int siege_cmd(unit * u, order * ord) resource_type *rt_catapultammo = NULL; resource_type *rt_catapult = NULL; - init_order(ord); + init_order_depr(ord); b = getbuilding(r); if (!b) { @@ -3928,9 +3808,9 @@ int siege_cmd(unit * u, order * ord) rt_catapult = rt_find("catapult"); d = i_get(u->items, rt_catapult->itype); - d = MIN(u->number, d); + if (d > u->number) d = u->number; pooled = get_pooled(u, rt_catapultammo, GET_DEFAULT, d); - d = MIN(pooled, d); + if (d > pooled) d = pooled; if (effskill(u, SK_CATAPULT, 0) >= 1) { katapultiere = d; d *= effskill(u, SK_CATAPULT, 0); @@ -3957,11 +3837,11 @@ int siege_cmd(unit * u, order * ord) * einheiten wieder abgesucht werden muessen! */ usetsiege(u, b); - b->besieged += MAX(bewaffnete, katapultiere); + if (katapultiere < bewaffnete) katapultiere = bewaffnete; + b->besieged += katapultiere; /* definitiver schaden eingeschraenkt */ - - d = MIN(d, b->size - 1); + if (d > b->size - 1) d = b->size - 1; /* meldung, schaden anrichten */ if (d && !curse_active(get_curse(b->attribs, &ct_magicwalls))) { @@ -4215,7 +4095,7 @@ void turn_process(void) init_processor(); process(); - if (config_get_int("modules.markets", 0)) { + if (markets_module()) { do_markets(); } } @@ -4227,7 +4107,7 @@ void turn_end(void) remove_empty_units(); /* must happen AFTER age, because that would destroy them right away */ - if (config_get_int("modules.wormholes", 0)) { + if (config_get_int("modules.wormhole", 0)) { wormholes_update(); } @@ -4248,7 +4128,7 @@ void update_subscriptions(void) FILE *F; char zText[4096]; - join_path(basepath(), "subscriptions", zText, sizeof(zText)); + path_join(basepath(), "subscriptions", zText, sizeof(zText)); F = fopen(zText, "r"); if (F == NULL) { log_warning(0, "could not open %s.\n", zText); @@ -4259,7 +4139,7 @@ void update_subscriptions(void) int subscription, fno; faction *f; - if (fscanf(F, "%d %4s", &subscription, zFaction) <= 0) + if (fscanf(F, "%4d %4s", &subscription, zFaction) <= 0) break; fno = atoi36(zFaction); f = findfaction(fno); @@ -4345,7 +4225,7 @@ bool cansee_unit(const unit * u, const unit * target, int modifier) else if (target->faction == u->faction) return true; else { - int n, rings, o; + int n, rings; if (is_guard(target) || usiege(target) || target->building || target->ship) { @@ -4362,7 +4242,7 @@ bool cansee_unit(const unit * u, const unit * target, int modifier) return false; } if (skill_enabled(SK_PERCEPTION)) { - o = effskill(u, SK_PERCEPTION, target->region); + int o = effskill(u, SK_PERCEPTION, target->region); if (o >= n) { return true; } @@ -4381,7 +4261,6 @@ cansee_durchgezogen(const faction * f, const region * r, const unit * u, /* und es muss niemand aus f in der region sein, wenn sie vom Turm * erblickt wird */ { - int n; unit *u2; if (fval(u_race(u), RCF_INVISIBLE) || u->number == 0) @@ -4389,7 +4268,7 @@ cansee_durchgezogen(const faction * f, const region * r, const unit * u, else if (u->faction == f) return true; else { - int rings; + int rings, n; if (is_guard(u) || usiege(u) || u->building || u->ship) { return true; diff --git a/src/laws.test.c b/src/laws.test.c index 942b673b0..5edde187d 100644 --- a/src/laws.test.c +++ b/src/laws.test.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -38,11 +39,11 @@ static void test_new_building_can_be_renamed(CuTest * tc) test_setup(); test_create_locale(); - r = test_create_region(0, 0, 0); + r = test_create_region(0, 0, NULL); b = test_create_building(r, NULL); CuAssertTrue(tc, !renamed_building(b)); - test_cleanup(); + test_teardown(); } static void test_rename_building(CuTest * tc) @@ -56,7 +57,7 @@ static void test_rename_building(CuTest * tc) test_setup(); test_create_locale(); btype = test_create_buildingtype("castle"); - r = test_create_region(0, 0, 0); + r = test_create_region(0, 0, NULL); b = new_building(btype, r, default_locale); f = test_create_faction(NULL); u = test_create_unit(f, r); @@ -65,7 +66,7 @@ static void test_rename_building(CuTest * tc) rename_building(u, NULL, b, "Villa Nagel"); CuAssertStrEquals(tc, "Villa Nagel", b->name); CuAssertTrue(tc, renamed_building(b)); - test_cleanup(); + test_teardown(); } static void test_rename_building_twice(CuTest * tc) @@ -79,7 +80,7 @@ static void test_rename_building_twice(CuTest * tc) test_setup(); test_create_locale(); btype = test_create_buildingtype("castle"); - r = test_create_region(0, 0, 0); + r = test_create_region(0, 0, NULL); b = new_building(btype, r, default_locale); f = test_create_faction(NULL); u = test_create_unit(f, r); @@ -90,7 +91,7 @@ static void test_rename_building_twice(CuTest * tc) rename_building(u, NULL, b, "Villa Kunterbunt"); CuAssertStrEquals(tc, "Villa Kunterbunt", b->name); - test_cleanup(); + test_teardown(); } static void test_contact(CuTest * tc) @@ -104,11 +105,11 @@ static void test_contact(CuTest * tc) test_setup(); test_create_locale(); btype = test_create_buildingtype("castle"); - r = test_create_region(0, 0, 0); + r = test_create_region(0, 0, NULL); b = new_building(btype, r, default_locale); - u1 = test_create_unit(test_create_faction(0), r); - u2 = test_create_unit(test_create_faction(0), r); - u3 = test_create_unit(test_create_faction(0), r); + u1 = test_create_unit(test_create_faction(NULL), r); + u2 = test_create_unit(test_create_faction(NULL), r); + u3 = test_create_unit(test_create_faction(NULL), r); set_level(u3, SK_PERCEPTION, 2); usetsiege(u3, b); b->besieged = 1; @@ -121,7 +122,7 @@ static void test_contact(CuTest * tc) CuAssertIntEquals(tc, HELP_GIVE, can_contact(r, u1, u2)); u_set_building(u2, b); CuAssertIntEquals(tc, 1, can_contact(r, u1, u2)); - test_cleanup(); + test_teardown(); } static void test_enter_building(CuTest * tc) @@ -133,7 +134,7 @@ static void test_enter_building(CuTest * tc) test_setup(); test_create_locale(); - r = test_create_region(0, 0, 0); + r = test_create_region(0, 0, NULL); rc = test_create_race("human"); u = test_create_unit(test_create_faction(rc), r); b = test_create_building(r, test_create_buildingtype("castle")); @@ -157,7 +158,7 @@ static void test_enter_building(CuTest * tc) CuAssertIntEquals(tc, 0, enter_building(u, NULL, b->no, true)); CuAssertPtrNotNull(tc, u->faction->msgs); - test_cleanup(); + test_teardown(); } static void test_enter_ship(CuTest * tc) @@ -167,13 +168,12 @@ static void test_enter_ship(CuTest * tc) ship *sh; race * rc; - test_cleanup(); - test_create_world(); + test_setup(); - r = findregion(0, 0); - rc = rc_get_or_create("human"); + r = test_create_region(0, 0, NULL); + rc = test_create_race("smurf"); u = test_create_unit(test_create_faction(rc), r); - sh = test_create_ship(r, st_get_or_create("boat")); + sh = test_create_ship(r, NULL); rc->flags = RCF_WALK; u->ship = 0; @@ -199,7 +199,7 @@ static void test_enter_ship(CuTest * tc) CuAssertIntEquals(tc, 0, enter_ship(u, NULL, sh->no, true)); CuAssertPtrNotNull(tc, u->faction->msgs); - test_cleanup(); + test_teardown(); } static void test_display_cmd(CuTest *tc) { @@ -208,9 +208,9 @@ static void test_display_cmd(CuTest *tc) { region *r; order *ord; - test_cleanup(); + test_setup(); r = test_create_region(0, 0, test_create_terrain("plain", LAND_REGION)); - f = test_create_faction(0); + f = test_create_faction(NULL); assert(r && f); u = test_create_unit(f, r); assert(u); @@ -230,7 +230,7 @@ static void test_display_cmd(CuTest *tc) { CuAssertPtrEquals(tc, NULL, r->land->display); free_order(ord); - test_cleanup(); + test_teardown(); } static void test_rule_force_leave(CuTest *tc) { @@ -247,7 +247,7 @@ static void test_rule_force_leave(CuTest *tc) { config_set("rules.owners.force_leave", "3"); CuAssertIntEquals(tc, true, rule_force_leave(FORCE_LEAVE_ALL)); CuAssertIntEquals(tc, true, rule_force_leave(FORCE_LEAVE_POSTCOMBAT)); - test_cleanup(); + test_teardown(); } static void test_force_leave_buildings(CuTest *tc) { @@ -255,9 +255,9 @@ static void test_force_leave_buildings(CuTest *tc) { region *r; unit *u1, *u2, *u3; building * b; - message *msg; test_setup(); + mt_register(mt_new_va("force_leave_building", "unit:unit", "owner:unit", "building:building", NULL)); r = test_create_region(0, 0, test_create_terrain("plain", LAND_REGION)); u1 = test_create_unit(test_create_faction(NULL), r); u2 = test_create_unit(u1->faction, r); @@ -271,24 +271,23 @@ static void test_force_leave_buildings(CuTest *tc) { CuAssertPtrEquals_Msg(tc, "owner should not be forced to leave", b, u1->building); CuAssertPtrEquals_Msg(tc, "same faction should not be forced to leave", b, u2->building); CuAssertPtrEquals_Msg(tc, "non-allies should be forced to leave", NULL, u3->building); - msg = test_get_last_message(u3->faction->msgs); - CuAssertStrEquals(tc, "force_leave_building", test_get_messagetype(msg)); + CuAssertPtrNotNull(tc, test_find_messagetype(u3->faction->msgs, "force_leave_building")); u_set_building(u3, b); al = ally_add(&u1->faction->allies, u3->faction); al->status = HELP_GUARD; force_leave(r, NULL); CuAssertPtrEquals_Msg(tc, "allies should not be forced to leave", b, u3->building); - test_cleanup(); + test_teardown(); } static void test_force_leave_ships(CuTest *tc) { region *r; unit *u1, *u2; ship *sh; - message *msg; test_setup(); + mt_register(mt_new_va("force_leave_ship", "unit:unit", "owner:unit", "ship:ship", NULL)); r = test_create_region(0, 0, test_create_terrain("plain", LAND_REGION)); u1 = test_create_unit(test_create_faction(NULL), r); u2 = test_create_unit(test_create_faction(NULL), r); @@ -298,9 +297,8 @@ static void test_force_leave_ships(CuTest *tc) { ship_set_owner(u1); force_leave(r, NULL); CuAssertPtrEquals_Msg(tc, "non-allies should be forced to leave", NULL, u2->ship); - msg = test_get_last_message(u2->faction->msgs); - CuAssertStrEquals(tc, "force_leave_ship", test_get_messagetype(msg)); - test_cleanup(); + CuAssertPtrNotNull(tc, test_find_messagetype(u2->faction->msgs, "force_leave_ship")); + test_teardown(); } static void test_force_leave_ships_on_ocean(CuTest *tc) { @@ -309,7 +307,7 @@ static void test_force_leave_ships_on_ocean(CuTest *tc) { ship *sh; test_setup(); - r = test_create_region(0, 0, test_create_terrain("ocean", SEA_REGION)); + r = test_create_ocean(0, 0); u1 = test_create_unit(test_create_faction(NULL), r); u2 = test_create_unit(test_create_faction(NULL), r); sh = test_create_ship(r, NULL); @@ -318,100 +316,95 @@ static void test_force_leave_ships_on_ocean(CuTest *tc) { ship_set_owner(u1); force_leave(r, NULL); CuAssertPtrEquals_Msg(tc, "no forcing out of ships on oceans", sh, u2->ship); - test_cleanup(); + test_teardown(); } static void test_fishing_feeds_2_people(CuTest * tc) { - const resource_type *rtype; + const item_type *itype; region *r; faction *f; unit *u; ship *sh; test_setup(); - test_create_world(); - r = findregion(-1, 0); - CuAssertStrEquals(tc, "ocean", r->terrain->_name); /* test_create_world needs coverage */ + r = test_create_ocean(0, 0); f = test_create_faction(NULL); u = test_create_unit(f, r); - sh = new_ship(st_find("boat"), r, 0); + sh = test_create_ship(r, NULL); u_set_ship(u, sh); - rtype = get_resourcetype(R_SILVER); - i_change(&u->items, rtype->itype, 42); + itype = test_create_silver(); + i_change(&u->items, itype, 42); scale_number(u, 1); sh->flags |= SF_FISHING; get_food(r); - CuAssertIntEquals(tc, 42, i_get(u->items, rtype->itype)); + CuAssertIntEquals(tc, 42, i_get(u->items, itype)); scale_number(u, 2); sh->flags |= SF_FISHING; get_food(r); - CuAssertIntEquals(tc, 42, i_get(u->items, rtype->itype)); + CuAssertIntEquals(tc, 42, i_get(u->items, itype)); scale_number(u, 3); sh->flags |= SF_FISHING; get_food(r); - CuAssertIntEquals(tc, 32, i_get(u->items, rtype->itype)); - test_cleanup(); + CuAssertIntEquals(tc, 32, i_get(u->items, itype)); + test_teardown(); } static void test_fishing_does_not_give_goblins_money(CuTest * tc) { - const resource_type *rtype; + const item_type *itype; region *r; faction *f; unit *u; ship *sh; test_setup(); - test_create_world(); - rtype = get_resourcetype(R_SILVER); + itype = test_create_silver(); - r = findregion(-1, 0); - CuAssertStrEquals(tc, "ocean", r->terrain->_name); /* test_create_world needs coverage */ + r = test_create_ocean(0, 0); f = test_create_faction(NULL); u = test_create_unit(f, r); - sh = new_ship(st_find("boat"), r, 0); + sh = test_create_ship(r, NULL); u_set_ship(u, sh); - i_change(&u->items, rtype->itype, 42); + i_change(&u->items, itype, 42); scale_number(u, 2); sh->flags |= SF_FISHING; get_food(r); - CuAssertIntEquals(tc, 42, i_get(u->items, rtype->itype)); - test_cleanup(); + CuAssertIntEquals(tc, 42, i_get(u->items, itype)); + test_teardown(); } static void test_fishing_gets_reset(CuTest * tc) { - const resource_type *rtype; + const item_type *itype; region *r; faction *f; unit *u; ship *sh; test_setup(); - test_create_world(); - rtype = get_resourcetype(R_SILVER); - r = findregion(-1, 0); - CuAssertStrEquals(tc, "ocean", r->terrain->_name); /* test_create_world needs coverage */ + itype = test_create_silver(); + + r = test_create_ocean(0, 0); f = test_create_faction(NULL); u = test_create_unit(f, r); - sh = new_ship(st_find("boat"), r, 0); + sh = test_create_ship(r, NULL); u_set_ship(u, sh); - i_change(&u->items, rtype->itype, 42); + i_change(&u->items, itype, 42); scale_number(u, 1); sh->flags |= SF_FISHING; get_food(r); - CuAssertIntEquals(tc, 42, i_get(u->items, rtype->itype)); + CuAssertIntEquals(tc, 42, i_get(u->items, itype)); scale_number(u, 1); get_food(r); - CuAssertIntEquals(tc, 32, i_get(u->items, rtype->itype)); - test_cleanup(); + CuAssertIntEquals(tc, 32, i_get(u->items, itype)); + test_teardown(); } static void test_unit_limit(CuTest * tc) @@ -425,7 +418,7 @@ static void test_unit_limit(CuTest * tc) config_set("rules.limit.alliance", "250"); CuAssertIntEquals(tc, 250, rule_alliance_limit()); - test_cleanup(); + test_teardown(); } static void test_maketemp(CuTest * tc) @@ -452,7 +445,7 @@ static void test_maketemp(CuTest * tc) CuAssertPtrNotNull(tc, u->orders); CuAssertPtrEquals(tc, NULL, u->orders->next); CuAssertIntEquals(tc, K_TAX, getkeyword(u->orders)); - test_cleanup(); + test_teardown(); } static void test_maketemp_default_order(CuTest * tc) @@ -482,7 +475,7 @@ static void test_maketemp_default_order(CuTest * tc) CuAssertPtrNotNull(tc, u->orders); CuAssertPtrEquals(tc, NULL, u->orders->next); CuAssertIntEquals(tc, K_TAX, getkeyword(u->orders)); - test_cleanup(); + test_teardown(); } static void test_limit_new_units(CuTest * tc) @@ -533,7 +526,7 @@ static void test_limit_new_units(CuTest * tc) CuAssertIntEquals(tc, 2, f->num_units); CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "too_many_units_in_alliance")); - test_cleanup(); + test_teardown(); } static void test_cannot_create_unit_above_limit(CuTest * tc) @@ -551,7 +544,7 @@ static void test_cannot_create_unit_above_limit(CuTest * tc) config_set("rules.limit.alliance", "3"); CuAssertIntEquals(tc, 0, checkunitnumber(f, 3)); CuAssertIntEquals(tc, 1, checkunitnumber(f, 4)); - test_cleanup(); + test_teardown(); } static void test_reserve_cmd(CuTest *tc) { @@ -580,7 +573,7 @@ static void test_reserve_cmd(CuTest *tc) { CuAssertIntEquals(tc, 200, i_get(u1->items, rtype->itype)); CuAssertIntEquals(tc, 0, i_get(u2->items, rtype->itype)); free_order(ord); - test_cleanup(); + test_teardown(); } struct pay_fixture { @@ -627,7 +620,7 @@ static void test_pay_cmd(CuTest *tc) { CuAssertIntEquals(tc, 0, pay_cmd(fix.u1, ord)); CuAssertIntEquals(tc, BLD_DONTPAY, b->flags&BLD_DONTPAY); free_order(ord); - test_cleanup(); + test_teardown(); } static void test_pay_cmd_other_building(CuTest *tc) { @@ -651,7 +644,7 @@ static void test_pay_cmd_other_building(CuTest *tc) { CuAssertIntEquals(tc, 0, pay_cmd(fix.u1, ord)); CuAssertIntEquals(tc, BLD_DONTPAY, b->flags&BLD_DONTPAY); free_order(ord); - test_cleanup(); + test_teardown(); } static void test_pay_cmd_must_be_owner(CuTest *tc) { @@ -670,7 +663,7 @@ static void test_pay_cmd_must_be_owner(CuTest *tc) { CuAssertIntEquals(tc, 0, pay_cmd(fix.u2, ord)); CuAssertIntEquals(tc, 0, b->flags&BLD_DONTPAY); free_order(ord); - test_cleanup(); + test_teardown(); } static void test_new_units(CuTest *tc) { @@ -695,7 +688,7 @@ static void test_new_units(CuTest *tc) { CuAssertIntEquals(tc, 0, u->age); CuAssertPtrEquals(tc, f, u->faction); CuAssertStrEquals(tc, "EINHEIT hurr", u->_name); - test_cleanup(); + test_teardown(); } typedef struct guard_fixture { @@ -719,9 +712,9 @@ void setup_guard(guard_fixture *fix, bool armed) { if (armed) { item_type *itype; itype = it_get_or_create(rt_get_or_create("sword")); - new_weapontype(itype, 0, frac_zero, NULL, 0, 0, 0, SK_MELEE, 2); + new_weapontype(itype, 0, frac_zero, NULL, 0, 0, 0, SK_MELEE); i_change(&u->items, itype, 1); - set_level(u, SK_MELEE, 2); + set_level(u, SK_MELEE, 1); } fix->u = u; } @@ -736,7 +729,7 @@ static void test_update_guards(CuTest *tc) { freset(fix.u, UFL_GUARD); update_guards(); CuAssertTrue(tc, !fval(fix.u, UFL_GUARD)); - test_cleanup(); + test_teardown(); } static void test_newbie_cannot_guard(CuTest *tc) { @@ -748,7 +741,7 @@ static void test_newbie_cannot_guard(CuTest *tc) { CuAssertIntEquals(tc, E_GUARD_NEWBIE, can_start_guarding(fix.u)); update_guards(); CuAssertTrue(tc, !fval(fix.u, UFL_GUARD)); - test_cleanup(); + test_teardown(); } static void test_unarmed_cannot_guard(CuTest *tc) { @@ -758,7 +751,7 @@ static void test_unarmed_cannot_guard(CuTest *tc) { CuAssertIntEquals(tc, E_GUARD_UNARMED, can_start_guarding(fix.u)); update_guards(); CuAssertTrue(tc, !fval(fix.u, UFL_GUARD)); - test_cleanup(); + test_teardown(); } static void test_unarmed_races_can_guard(CuTest *tc) { @@ -771,7 +764,7 @@ static void test_unarmed_races_can_guard(CuTest *tc) { CuAssertIntEquals(tc, E_GUARD_OK, can_start_guarding(fix.u)); update_guards(); CuAssertTrue(tc, fval(fix.u, UFL_GUARD)); - test_cleanup(); + test_teardown(); } static void test_monsters_can_guard(CuTest *tc) { @@ -782,18 +775,18 @@ static void test_monsters_can_guard(CuTest *tc) { CuAssertIntEquals(tc, E_GUARD_OK, can_start_guarding(fix.u)); update_guards(); CuAssertTrue(tc, fval(fix.u, UFL_GUARD)); - test_cleanup(); + test_teardown(); } -static void test_low_skill_cannot_guard(CuTest *tc) { +static void test_unskilled_cannot_guard(CuTest *tc) { guard_fixture fix; setup_guard(&fix, true); - set_level(fix.u, SK_MELEE, 1); + set_level(fix.u, SK_MELEE, 0); CuAssertIntEquals(tc, E_GUARD_UNARMED, can_start_guarding(fix.u)); update_guards(); CuAssertTrue(tc, !fval(fix.u, UFL_GUARD)); - test_cleanup(); + test_teardown(); } static void test_fleeing_cannot_guard(CuTest *tc) { @@ -804,7 +797,7 @@ static void test_fleeing_cannot_guard(CuTest *tc) { CuAssertIntEquals(tc, E_GUARD_FLEEING, can_start_guarding(fix.u)); update_guards(); CuAssertTrue(tc, !fval(fix.u, UFL_GUARD)); - test_cleanup(); + test_teardown(); } static void test_reserve_self(CuTest *tc) { @@ -821,7 +814,7 @@ static void test_reserve_self(CuTest *tc) { rtype = get_resourcetype(R_SILVER); assert(rtype && rtype->itype); f = test_create_faction(NULL); - r = test_create_region(0, 0, 0); + r = test_create_region(0, 0, NULL); assert(r && f); u1 = test_create_unit(f, r); u2 = test_create_unit(f, r); @@ -836,7 +829,7 @@ static void test_reserve_self(CuTest *tc) { CuAssertIntEquals(tc, 100, i_get(u1->items, rtype->itype)); CuAssertIntEquals(tc, 100, i_get(u2->items, rtype->itype)); free_order(ord); - test_cleanup(); + test_teardown(); } static void statistic_test(CuTest *tc, int peasants, int luck, int maxp, @@ -861,7 +854,20 @@ static void test_peasant_luck_effect(CuTest *tc) { config_set("rules.peasants.growth.factor", "1"); statistic_test(tc, 1000, 1000, 1000, 0, 501, 501); - test_cleanup(); + test_teardown(); +} + +/** +* Create any terrain types that are used by demographics. +* +* This should prevent newterrain from returning NULL. +*/ +static void setup_terrains(CuTest *tc) { + test_create_terrain("volcano", SEA_REGION | SWIM_INTO | FLY_INTO); + test_create_terrain("activevolcano", LAND_REGION | WALK_INTO | FLY_INTO); + init_terrains(); + CuAssertPtrNotNull(tc, newterrain(T_VOLCANO)); + CuAssertPtrNotNull(tc, newterrain(T_VOLCANO_SMOKING)); } static void test_luck_message(CuTest *tc) { @@ -869,6 +875,8 @@ static void test_luck_message(CuTest *tc) { attrib *a; test_setup(); + mt_register(mt_new_va("peasantluck_success", "births:int", NULL)); + setup_terrains(tc); r = test_create_region(0, 0, NULL); rsetpeasants(r, 1); @@ -885,15 +893,17 @@ static void test_luck_message(CuTest *tc) { CuAssertPtrNotNull(tc, test_find_messagetype(r->msgs, "peasantluck_success")); - test_cleanup(); + test_teardown(); } static unit * setup_name_cmd(void) { faction *f; test_setup(); - f = test_create_faction(0); - return test_create_unit(f, test_create_region(0, 0, 0)); + mt_register(mt_new_va("renamed_building_seen", "renamer:unit", "region:region", "building:building", NULL)); + mt_register(mt_new_va("renamed_building_notseen", "region:region", "building:building", NULL)); + f = test_create_faction(NULL); + return test_create_unit(f, test_create_region(0, 0, NULL)); } static void test_name_unit(CuTest *tc) { @@ -914,7 +924,7 @@ static void test_name_unit(CuTest *tc) { CuAssertStrEquals(tc, "Hodor", u->_name); free_order(ord); - test_cleanup(); + test_teardown(); } static void test_name_region(CuTest *tc) { @@ -926,7 +936,7 @@ static void test_name_region(CuTest *tc) { f = u->faction; ord = create_order(K_NAME, f->locale, "%s Hodor", LOC(f->locale, parameters[P_REGION])); - u_set_building(u, test_create_building(u->region, 0)); + u_set_building(u, test_create_building(u->region, NULL)); name_cmd(u, ord); CuAssertStrEquals(tc, "Hodor", u->region->land->name); free_order(ord); @@ -937,61 +947,90 @@ static void test_name_region(CuTest *tc) { CuAssertStrEquals(tc, "Hodor", u->region->land->name); free_order(ord); - test_cleanup(); + test_teardown(); } static void test_name_building(CuTest *tc) { - unit *u; + unit *uo, *u, *ux; faction *f; - order *ord; u = setup_name_cmd(); + u->building = test_create_building(u->region, NULL); f = u->faction; + uo = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); + u_set_building(uo, u->building); + ux = test_create_unit(f, test_create_region(0, 0, NULL)); + u_set_building(ux, u->building); - ord = create_order(K_NAME, f->locale, "%s Hodor", LOC(f->locale, parameters[P_BUILDING])); - name_cmd(u, ord); - CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error145")); + u->thisorder = create_order(K_NAME, f->locale, "%s Hodor", LOC(f->locale, parameters[P_BUILDING])); - u->building = test_create_building(u->region, 0); - name_cmd(u, ord); + building_set_owner(uo); + name_cmd(u, u->thisorder); + CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error148")); + test_clear_messages(f); + + building_set_owner(u); + name_cmd(u, u->thisorder); CuAssertStrEquals(tc, "Hodor", u->building->name); - free_order(ord); - ord = create_order(K_NAME, f->locale, LOC(f->locale, parameters[P_BUILDING])); - name_cmd(u, ord); + building_setname(u->building, "Home"); + building_set_owner(ux); + name_cmd(u, u->thisorder); + CuAssertPtrEquals(tc, NULL, test_find_messagetype(f->msgs, "error148")); + CuAssertStrEquals(tc, "Hodor", u->building->name); + + test_clear_messages(f); + free_order(u->thisorder); + u->thisorder = create_order(K_NAME, f->locale, LOC(f->locale, parameters[P_BUILDING])); + name_cmd(u, u->thisorder); CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error84")); CuAssertStrEquals(tc, "Hodor", u->building->name); - free_order(ord); /* TODO: test BTF_NAMECHANGE: btype->flags |= BTF_NAMECHANGE; CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "error278")); test_clear_messages(u->faction); name_cmd(u, ord); */ - test_cleanup(); + test_teardown(); } static void test_name_ship(CuTest *tc) { - unit *u; + unit *uo, *u, *ux; faction *f; - order *ord; u = setup_name_cmd(); + u->ship = test_create_ship(u->region, NULL); f = u->faction; - u->ship = test_create_ship(u->region, 0); + uo = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); + u_set_ship(uo, u->ship); + ux = test_create_unit(f, test_create_region(0, 0, NULL)); + u_set_ship(ux, u->ship); - ord = create_order(K_NAME, f->locale, "%s Hodor", LOC(f->locale, parameters[P_SHIP])); - name_cmd(u, ord); + u->thisorder = create_order(K_NAME, f->locale, "%s Hodor", LOC(f->locale, parameters[P_SHIP])); + + ship_set_owner(uo); + name_cmd(u, u->thisorder); + CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error12")); + test_clear_messages(f); + + ship_set_owner(u); + name_cmd(u, u->thisorder); CuAssertStrEquals(tc, "Hodor", u->ship->name); - free_order(ord); - ord = create_order(K_NAME, f->locale, LOC(f->locale, parameters[P_SHIP])); - name_cmd(u, ord); + ship_setname(u->ship, "Titanic"); + ship_set_owner(ux); + name_cmd(u, u->thisorder); + CuAssertPtrEquals(tc, NULL, test_find_messagetype(f->msgs, "error12")); + CuAssertStrEquals(tc, "Hodor", u->ship->name); + + test_clear_messages(f); + free_order(u->thisorder); + u->thisorder = create_order(K_NAME, f->locale, LOC(f->locale, parameters[P_SHIP])); + name_cmd(u, u->thisorder); CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error84")); CuAssertStrEquals(tc, "Hodor", u->ship->name); - free_order(ord); - test_cleanup(); + test_teardown(); } static void test_long_order_normal(CuTest *tc) { @@ -1000,94 +1039,94 @@ static void test_long_order_normal(CuTest *tc) { order *ord; test_setup(); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); fset(u, UFL_MOVED); fset(u, UFL_LONGACTION); unit_addorder(u, ord = create_order(K_MOVE, u->faction->locale, 0)); update_long_order(u); - CuAssertPtrEquals(tc, ord->data, u->thisorder->data); + CuAssertIntEquals(tc, ord->id, u->thisorder->id); CuAssertIntEquals(tc, 0, fval(u, UFL_MOVED)); CuAssertIntEquals(tc, 0, fval(u, UFL_LONGACTION)); CuAssertPtrNotNull(tc, u->orders); CuAssertPtrEquals(tc, 0, u->faction->msgs); CuAssertPtrEquals(tc, 0, u->old_orders); - test_cleanup(); + test_teardown(); } static void test_long_order_none(CuTest *tc) { /* TODO: write more tests */ unit *u; test_setup(); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); update_long_order(u); CuAssertPtrEquals(tc, 0, u->thisorder); CuAssertPtrEquals(tc, 0, u->orders); CuAssertPtrEquals(tc, 0, u->faction->msgs); - test_cleanup(); + test_teardown(); } static void test_long_order_cast(CuTest *tc) { /* TODO: write more tests */ unit *u; test_setup(); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); - unit_addorder(u, create_order(K_CAST, u->faction->locale, 0)); - unit_addorder(u, create_order(K_CAST, u->faction->locale, 0)); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); + unit_addorder(u, create_order(K_CAST, u->faction->locale, NULL)); + unit_addorder(u, create_order(K_CAST, u->faction->locale, NULL)); update_long_order(u); CuAssertPtrEquals(tc, 0, u->thisorder); CuAssertPtrNotNull(tc, u->orders); CuAssertPtrEquals(tc, 0, u->faction->msgs); - test_cleanup(); + test_teardown(); } static void test_long_order_buy_sell(CuTest *tc) { /* TODO: write more tests */ unit *u; test_setup(); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); - unit_addorder(u, create_order(K_BUY, u->faction->locale, 0)); - unit_addorder(u, create_order(K_SELL, u->faction->locale, 0)); - unit_addorder(u, create_order(K_SELL, u->faction->locale, 0)); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); + unit_addorder(u, create_order(K_BUY, u->faction->locale, NULL)); + unit_addorder(u, create_order(K_SELL, u->faction->locale, NULL)); + unit_addorder(u, create_order(K_SELL, u->faction->locale, NULL)); update_long_order(u); CuAssertPtrEquals(tc, 0, u->thisorder); CuAssertPtrNotNull(tc, u->orders); CuAssertPtrEquals(tc, 0, u->faction->msgs); - test_cleanup(); + test_teardown(); } static void test_long_order_multi_long(CuTest *tc) { /* TODO: write more tests */ unit *u; test_setup(); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); - unit_addorder(u, create_order(K_MOVE, u->faction->locale, 0)); - unit_addorder(u, create_order(K_DESTROY, u->faction->locale, 0)); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); + unit_addorder(u, create_order(K_MOVE, u->faction->locale, NULL)); + unit_addorder(u, create_order(K_DESTROY, u->faction->locale, NULL)); update_long_order(u); CuAssertPtrNotNull(tc, u->thisorder); CuAssertPtrNotNull(tc, u->orders); CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "error52")); - test_cleanup(); + test_teardown(); } static void test_long_order_multi_buy(CuTest *tc) { /* TODO: write more tests */ unit *u; test_setup(); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); unit_addorder(u, create_order(K_BUY, u->faction->locale, 0)); unit_addorder(u, create_order(K_BUY, u->faction->locale, 0)); update_long_order(u); CuAssertPtrEquals(tc, 0, u->thisorder); CuAssertPtrNotNull(tc, u->orders); CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "error52")); - test_cleanup(); + test_teardown(); } static void test_long_order_multi_sell(CuTest *tc) { /* TODO: write more tests */ unit *u; test_setup(); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); unit_addorder(u, create_order(K_SELL, u->faction->locale, 0)); unit_addorder(u, create_order(K_BUY, u->faction->locale, 0)); unit_addorder(u, create_order(K_SELL, u->faction->locale, 0)); @@ -1095,28 +1134,28 @@ static void test_long_order_multi_sell(CuTest *tc) { CuAssertPtrEquals(tc, 0, u->thisorder); CuAssertPtrNotNull(tc, u->orders); CuAssertPtrEquals(tc, 0, u->faction->msgs); - test_cleanup(); + test_teardown(); } static void test_long_order_buy_cast(CuTest *tc) { /* TODO: write more tests */ unit *u; test_setup(); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); unit_addorder(u, create_order(K_BUY, u->faction->locale, 0)); unit_addorder(u, create_order(K_CAST, u->faction->locale, 0)); update_long_order(u); CuAssertPtrEquals(tc, 0, u->thisorder); CuAssertPtrNotNull(tc, u->orders); CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "error52")); - test_cleanup(); + test_teardown(); } static void test_long_order_hungry(CuTest *tc) { unit *u; test_setup(); config_set("hunger.long", "1"); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); fset(u, UFL_HUNGER); unit_addorder(u, create_order(K_MOVE, u->faction->locale, 0)); unit_addorder(u, create_order(K_DESTROY, u->faction->locale, 0)); @@ -1125,7 +1164,7 @@ static void test_long_order_hungry(CuTest *tc) { CuAssertIntEquals(tc, K_WORK, getkeyword(u->thisorder)); CuAssertPtrNotNull(tc, u->orders); CuAssertPtrEquals(tc, 0, u->faction->msgs); - test_cleanup(); + test_teardown(); } static void test_ally_cmd_errors(CuTest *tc) { @@ -1134,7 +1173,7 @@ static void test_ally_cmd_errors(CuTest *tc) { order *ord; test_setup(); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); fid = u->faction->no + 1; CuAssertPtrEquals(tc, 0, findfaction(fid)); @@ -1143,16 +1182,18 @@ static void test_ally_cmd_errors(CuTest *tc) { CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "error66")); free_order(ord); - test_cleanup(); + test_teardown(); } static void test_name_cmd(CuTest *tc) { unit *u; faction *f; + alliance *al; order *ord; test_setup(); - u = test_create_unit(f = test_create_faction(0), test_create_region(0, 0, 0)); + u = test_create_unit(f = test_create_faction(NULL), test_create_region(0, 0, NULL)); + setalliance(f, al = makealliance(42, "")); ord = create_order(K_NAME, f->locale, "%s ' Ho\tdor '", LOC(f->locale, parameters[P_UNIT])); name_cmd(u, ord); @@ -1165,13 +1206,13 @@ static void test_name_cmd(CuTest *tc) { free_order(ord); ord = create_order(K_NAME, f->locale, "%s ' Ho\tdor '", LOC(f->locale, parameters[P_SHIP])); - u->ship = test_create_ship(u->region, 0); + u->ship = test_create_ship(u->region, NULL); name_cmd(u, ord); CuAssertStrEquals(tc, "Hodor", u->ship->name); free_order(ord); ord = create_order(K_NAME, f->locale, "%s ' Ho\tdor '", LOC(f->locale, parameters[P_BUILDING])); - u_set_building(u, test_create_building(u->region, 0)); + u_set_building(u, test_create_building(u->region, NULL)); name_cmd(u, ord); CuAssertStrEquals(tc, "Hodor", u->building->name); free_order(ord); @@ -1181,7 +1222,12 @@ static void test_name_cmd(CuTest *tc) { CuAssertStrEquals(tc, "Hodor", u->region->land->name); free_order(ord); - test_cleanup(); + ord = create_order(K_NAME, f->locale, "%s ' Ho\tdor '", LOC(f->locale, parameters[P_ALLIANCE])); + name_cmd(u, ord); + CuAssertStrEquals(tc, "Hodor", al->name); + free_order(ord); + + test_teardown(); } static void test_name_cmd_2274(CuTest *tc) { @@ -1190,9 +1236,9 @@ static void test_name_cmd_2274(CuTest *tc) { region *r; test_setup(); - r = test_create_region(0, 0, 0); - u1 = test_create_unit(test_create_faction(0), r); - u2 = test_create_unit(test_create_faction(0), r); + r = test_create_region(0, 0, NULL); + u1 = test_create_unit(test_create_faction(NULL), r); + u2 = test_create_unit(test_create_faction(NULL), r); u3 = test_create_unit(u2->faction, r); u_set_building(u1, test_create_building(r, NULL)); u1->building->size = 10; @@ -1212,7 +1258,7 @@ static void test_name_cmd_2274(CuTest *tc) { name_cmd(u1, u1->thisorder); CuAssertStrEquals(tc, "Hodor", r->land->name); - test_cleanup(); + test_teardown(); } static void test_ally_cmd(CuTest *tc) { @@ -1221,8 +1267,8 @@ static void test_ally_cmd(CuTest *tc) { order *ord; test_setup(); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); - f = test_create_faction(0); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); + f = test_create_faction(NULL); ord = create_order(K_ALLY, f->locale, "%s", itoa36(f->no)); ally_cmd(u, ord); @@ -1248,15 +1294,18 @@ static void test_ally_cmd(CuTest *tc) { CuAssertIntEquals(tc, 0, alliedfaction(0, u->faction, f, HELP_ALL)); free_order(ord); - test_cleanup(); + test_teardown(); } static void test_nmr_warnings(CuTest *tc) { faction *f1, *f2; test_setup(); + mt_register(mt_new_va("nmr_warning", NULL)); + mt_register(mt_new_va("nmr_warning_final", NULL)); + mt_register(mt_new_va("warn_dropout", "faction:faction", "turn:int", NULL)); config_set("nmr.timeout", "3"); - f1 = test_create_faction(0); - f2 = test_create_faction(0); + f1 = test_create_faction(NULL); + f2 = test_create_faction(NULL); f2->age = 2; f2->lastorders = 1; turn = 3; @@ -1268,15 +1317,18 @@ static void test_nmr_warnings(CuTest *tc) { CuAssertPtrNotNull(tc, f2->msgs->begin); CuAssertPtrNotNull(tc, test_find_messagetype(f2->msgs, "nmr_warning")); CuAssertPtrNotNull(tc, test_find_messagetype(f2->msgs, "nmr_warning_final")); - test_cleanup(); + test_teardown(); } static unit * setup_mail_cmd(void) { faction *f; test_setup(); - f = test_create_faction(0); - return test_create_unit(f, test_create_region(0, 0, 0)); + mt_register(mt_new_va("regionmessage", "region:region", "sender:unit", "string:string", NULL)); + mt_register(mt_new_va("unitmessage", "region:region", "sender:unit", "string:string", "unit:unit", NULL)); + mt_register(mt_new_va("mail_result", "message:string", "unit:unit", NULL)); + f = test_create_faction(NULL); + return test_create_unit(f, test_create_region(0, 0, NULL)); } static void test_mail_unit(CuTest *tc) { @@ -1290,7 +1342,7 @@ static void test_mail_unit(CuTest *tc) { mail_cmd(u, ord); CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "unitmessage")); free_order(ord); - test_cleanup(); + test_teardown(); } static void test_mail_faction(CuTest *tc) { @@ -1304,7 +1356,7 @@ static void test_mail_faction(CuTest *tc) { mail_cmd(u, ord); CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "regionmessage")); free_order(ord); - test_cleanup(); + test_teardown(); } static void test_mail_region(CuTest *tc) { @@ -1318,7 +1370,7 @@ static void test_mail_region(CuTest *tc) { mail_cmd(u, ord); CuAssertPtrNotNull(tc, test_find_messagetype(u->region->msgs, "mail_result")); free_order(ord); - test_cleanup(); + test_teardown(); } static void test_mail_unit_no_msg(CuTest *tc) { @@ -1333,7 +1385,7 @@ static void test_mail_unit_no_msg(CuTest *tc) { CuAssertPtrEquals(tc, 0, test_find_messagetype(f->msgs, "unitmessage")); CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error30")); free_order(ord); - test_cleanup(); + test_teardown(); } static void test_mail_faction_no_msg(CuTest *tc) { @@ -1348,7 +1400,7 @@ static void test_mail_faction_no_msg(CuTest *tc) { CuAssertPtrEquals(tc, 0, test_find_messagetype(f->msgs, "regionmessage")); CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error30")); free_order(ord); - test_cleanup(); + test_teardown(); } static void test_mail_faction_no_target(CuTest *tc) { @@ -1363,7 +1415,7 @@ static void test_mail_faction_no_target(CuTest *tc) { CuAssertPtrEquals(tc, 0, test_find_messagetype(f->msgs, "regionmessage")); CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error66")); free_order(ord); - test_cleanup(); + test_teardown(); } static void test_mail_region_no_msg(CuTest *tc) { @@ -1378,7 +1430,7 @@ static void test_mail_region_no_msg(CuTest *tc) { CuAssertPtrEquals(tc, 0, test_find_messagetype(u->region->msgs, "mail_result")); CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error30")); free_order(ord); - test_cleanup(); + test_teardown(); } static void test_show_without_item(CuTest *tc) @@ -1391,6 +1443,7 @@ static void test_show_without_item(CuTest *tc) struct locale *loc; test_setup(); + mt_register(mt_new_va("displayitem", "weight:int", "item:resource", "description:string", NULL)); loc = get_or_create_locale("de"); locale_setstring(loc, parameters[P_ANY], "ALLE"); @@ -1423,7 +1476,7 @@ static void test_show_without_item(CuTest *tc) test_clear_messages(f); free_order(ord); - test_cleanup(); + test_teardown(); } static void test_show_race(CuTest *tc) { @@ -1435,7 +1488,7 @@ static void test_show_race(CuTest *tc) { test_setup(); - mt_register(mt_new_va("msg_event", "string:string", 0)); + mt_register(mt_new_va("msg_event", "string:string", NULL)); test_create_race("human"); rc = test_create_race("elf"); @@ -1445,7 +1498,7 @@ static void test_show_race(CuTest *tc) { locale_setstring(loc, "race::human_p", "Menschen"); locale_setstring(loc, "race::human", "Mensch"); init_locale(loc); - u = test_create_unit(test_create_faction(rc), test_create_region(0, 0, 0)); + u = test_create_unit(test_create_faction(rc), test_create_region(0, 0, NULL)); u->faction->locale = loc; ord = create_order(K_RESHOW, loc, "Mensch"); @@ -1464,7 +1517,7 @@ static void test_show_race(CuTest *tc) { test_clear_messages(u->faction); free_order(ord); - test_cleanup(); + test_teardown(); } static void test_show_both(CuTest *tc) { @@ -1474,10 +1527,9 @@ static void test_show_both(CuTest *tc) { struct locale *loc; message * msg; - test_cleanup(); - - mt_register(mt_new_va("msg_event", "string:string", 0)); - mt_register(mt_new_va("displayitem", "weight:int", "item:resource", "description:string", 0)); + test_setup(); + mt_register(mt_new_va("msg_event", "string:string", NULL)); + mt_register(mt_new_va("displayitem", "weight:int", "item:resource", "description:string", NULL)); rc = test_create_race("elf"); test_create_itemtype("elvenhorse"); @@ -1492,7 +1544,7 @@ static void test_show_both(CuTest *tc) { CuAssertPtrNotNull(tc, finditemtype("elf", loc)); CuAssertPtrNotNull(tc, findrace("elf", loc)); - u = test_create_unit(test_create_faction(rc), test_create_region(0, 0, 0)); + u = test_create_unit(test_create_faction(rc), test_create_region(0, 0, NULL)); u->faction->locale = loc; i_change(&u->items, finditemtype("elfenpferd", loc), 1); ord = create_order(K_RESHOW, loc, "Elf"); @@ -1506,7 +1558,7 @@ static void test_show_both(CuTest *tc) { CuAssertTrue(tc, memcmp("Hiyaa!", msg->parameters[2].v, 4) == 0); test_clear_messages(u->faction); free_order(ord); - test_cleanup(); + test_teardown(); } static void test_immigration(CuTest * tc) @@ -1515,7 +1567,7 @@ static void test_immigration(CuTest * tc) double inject[] = { 1 }; test_setup(); - r = test_create_region(0, 0, 0); + r = test_create_region(0, 0, NULL); rsetpeasants(r, 0); config_set("rules.economy.repopulate_maximum", 0); @@ -1536,7 +1588,7 @@ static void test_immigration(CuTest * tc) immigration(); CuAssertIntEquals(tc, 2, rpeasants(r)); - test_cleanup(); + test_teardown(); } static void test_demon_hunger(CuTest * tc) @@ -1546,17 +1598,16 @@ static void test_demon_hunger(CuTest * tc) race *rc; faction *f; unit *u; - message* msg; test_setup(); init_resources(); - r = test_create_region(0, 0, 0); + r = test_create_region(0, 0, NULL); rc = test_create_race("demon"); f = test_create_faction(rc); u = test_create_unit(f, r); u->hp = 999; - config_set("hunger.demons.peasant_tolerance", "1"); + config_set("hunger.demon.peasant_tolerance", "1"); rtype = get_resourcetype(R_SILVER); i_change(&u->items, rtype->itype, 30); @@ -1568,15 +1619,14 @@ static void test_demon_hunger(CuTest * tc) CuAssertIntEquals(tc, 20, i_get(u->items, rtype->itype)); CuAssertPtrEquals(tc, 0, test_find_messagetype(f->msgs, "malnourish")); - config_set("hunger.demons.peasant_tolerance", "0"); + config_set("hunger.demon.peasant_tolerance", "0"); get_food(r); CuAssertIntEquals(tc, 10, i_get(u->items, rtype->itype)); - msg = test_get_last_message(u->faction->msgs); - CuAssertStrEquals(tc, "malnourish", test_get_messagetype(msg)); + CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "malnourish")); - test_cleanup(); + test_teardown(); } static void test_armedmen(CuTest *tc) { @@ -1585,9 +1635,9 @@ static void test_armedmen(CuTest *tc) { item_type *it_sword; weapon_type *wtype; test_setup(); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); it_sword = test_create_itemtype("sword"); - wtype = new_weapontype(it_sword, 0, frac_make(1, 2), 0, 0, 0, 0, SK_MELEE, 1); + wtype = new_weapontype(it_sword, 0, frac_make(1, 2), 0, 0, 0, 0, SK_MELEE); CuAssertIntEquals(tc, 0, armedmen(u, false)); CuAssertIntEquals(tc, 0, armedmen(u, true)); set_level(u, SK_MELEE, 1); @@ -1604,23 +1654,18 @@ static void test_armedmen(CuTest *tc) { set_level(u, SK_MELEE, 1); i_change(&u->items, it_sword, -1); CuAssertIntEquals(tc, 1, armedmen(u, false)); - wtype->minskill = 2; - CuAssertIntEquals(tc, 0, armedmen(u, false)); - set_level(u, SK_MELEE, 2); - CuAssertIntEquals(tc, 1, armedmen(u, false)); - CuAssertIntEquals(tc, 1, armedmen(u, true)); wtype->flags |= WTF_SIEGE; CuAssertIntEquals(tc, 0, armedmen(u, false)); CuAssertIntEquals(tc, 1, armedmen(u, true)); - test_cleanup(); + test_teardown(); } static void test_cansee(CuTest *tc) { unit *u, *u2; test_setup(); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); - u2 = test_create_unit(test_create_faction(0), u->region); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); + u2 = test_create_unit(test_create_faction(NULL), u->region); CuAssertTrue(tc, cansee(u->faction, u->region, u2, 0)); @@ -1630,26 +1675,7 @@ static void test_cansee(CuTest *tc) { set_level(u, SK_PERCEPTION, 1); CuAssertTrue(tc, cansee(u->faction, u->region, u2, 0)); - test_cleanup(); -} - -static void test_cansee_spell(CuTest *tc) { - unit *u2; - faction *f; - - test_setup(); - f = test_create_faction(0); - u2 = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); - - CuAssertTrue(tc, cansee_ex(f, u2->region, u2, 0, seen_spell)); - CuAssertTrue(tc, cansee_ex(f, u2->region, u2, 0, seen_battle)); - - set_level(u2, SK_STEALTH, 1); - CuAssertTrue(tc, !cansee_ex(f, u2->region, u2, 0, seen_spell)); - CuAssertTrue(tc, cansee_ex(f, u2->region, u2, 1, seen_spell)); - CuAssertTrue(tc, cansee_ex(f, u2->region, u2, 1, seen_battle)); - - test_cleanup(); + test_teardown(); } static void test_cansee_ring(CuTest *tc) { @@ -1657,8 +1683,8 @@ static void test_cansee_ring(CuTest *tc) { item_type *itype[2]; test_setup(); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); - u2 = test_create_unit(test_create_faction(0), u->region); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); + u2 = test_create_unit(test_create_faction(NULL), u->region); scale_number(u2, 2); itype[0] = test_create_itemtype("roi"); @@ -1682,7 +1708,7 @@ static void test_cansee_ring(CuTest *tc) { i_change(&u->items, itype[1], 1); CuAssertTrue(tc, cansee(u->faction, u->region, u2, 0)); - test_cleanup(); + test_teardown(); } static void test_cansee_sphere(CuTest *tc) { @@ -1690,8 +1716,8 @@ static void test_cansee_sphere(CuTest *tc) { item_type *itype[2]; test_setup(); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); - u2 = test_create_unit(test_create_faction(0), u->region); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); + u2 = test_create_unit(test_create_faction(NULL), u->region); itype[0] = test_create_itemtype("sphereofinv"); itype[1] = test_create_itemtype("aots"); @@ -1715,7 +1741,7 @@ static void test_cansee_sphere(CuTest *tc) { scale_number(u2, 99); CuAssertTrue(tc, cansee(u->faction, u->region, u2, 0)); - test_cleanup(); + test_teardown(); } CuSuite *get_laws_suite(void) @@ -1727,6 +1753,10 @@ CuSuite *get_laws_suite(void) SUITE_ADD_TEST(suite, test_ally_cmd); SUITE_ADD_TEST(suite, test_name_cmd); SUITE_ADD_TEST(suite, test_name_cmd_2274); + SUITE_ADD_TEST(suite, test_name_unit); + SUITE_ADD_TEST(suite, test_name_region); + SUITE_ADD_TEST(suite, test_name_building); + SUITE_ADD_TEST(suite, test_name_ship); SUITE_ADD_TEST(suite, test_ally_cmd_errors); SUITE_ADD_TEST(suite, test_long_order_normal); SUITE_ADD_TEST(suite, test_long_order_none); @@ -1751,7 +1781,7 @@ CuSuite *get_laws_suite(void) SUITE_ADD_TEST(suite, test_unarmed_races_can_guard); SUITE_ADD_TEST(suite, test_monsters_can_guard); SUITE_ADD_TEST(suite, test_fleeing_cannot_guard); - SUITE_ADD_TEST(suite, test_low_skill_cannot_guard); + SUITE_ADD_TEST(suite, test_unskilled_cannot_guard); SUITE_ADD_TEST(suite, test_reserve_self); SUITE_ADD_TEST(suite, test_reserve_cmd); SUITE_ADD_TEST(suite, test_pay_cmd); @@ -1776,10 +1806,6 @@ CuSuite *get_laws_suite(void) SUITE_ADD_TEST(suite, test_mail_region_no_msg); SUITE_ADD_TEST(suite, test_mail_faction_no_target); SUITE_ADD_TEST(suite, test_luck_message); - SUITE_ADD_TEST(suite, test_name_unit); - SUITE_ADD_TEST(suite, test_name_region); - SUITE_ADD_TEST(suite, test_name_building); - SUITE_ADD_TEST(suite, test_name_ship); SUITE_ADD_TEST(suite, test_show_without_item); SUITE_ADD_TEST(suite, test_show_race); SUITE_ADD_TEST(suite, test_show_both); @@ -1789,7 +1815,6 @@ CuSuite *get_laws_suite(void) SUITE_ADD_TEST(suite, test_cansee); SUITE_ADD_TEST(suite, test_cansee_ring); SUITE_ADD_TEST(suite, test_cansee_sphere); - SUITE_ADD_TEST(suite, test_cansee_spell); return suite; } diff --git a/src/lighthouse.c b/src/lighthouse.c index ad0cd639a..fbf950fb1 100644 --- a/src/lighthouse.c +++ b/src/lighthouse.c @@ -72,7 +72,7 @@ int lighthouse_range(const building * b, const faction * f, const unit *u) int sk = effskill(u, SK_PERCEPTION, 0) / 3; assert(u->building == b); assert(u->faction == f); - maxd = MIN(maxd, sk); + if (maxd > sk) maxd = sk; } /* E3A rule: no perception req'd */ return maxd; diff --git a/src/lighthouse.test.c b/src/lighthouse.test.c index 6105d25b9..e0c57ec1a 100644 --- a/src/lighthouse.test.c +++ b/src/lighthouse.test.c @@ -21,10 +21,10 @@ static void test_lighthouse_range(CuTest * tc) building *b; test_setup(); - r = test_create_region(0, 0, 0); + r = test_create_region(0, 0, NULL); test_create_region(1, 0, 0); - u1 = test_create_unit(test_create_faction(0), r); - u2 = test_create_unit(test_create_faction(0), r); + u1 = test_create_unit(test_create_faction(NULL), r); + u2 = test_create_unit(test_create_faction(NULL), r); b = test_create_building(r, test_create_buildingtype("lighthouse")); CuAssertIntEquals(tc, 0, lighthouse_range(b, NULL, NULL)); CuAssertIntEquals(tc, 0, lighthouse_range(b, u1->faction, NULL)); @@ -49,7 +49,7 @@ static void test_lighthouse_range(CuTest * tc) set_level(u1, SK_PERCEPTION, 9); CuAssertIntEquals(tc, 3, lighthouse_range(b, u1->faction, u1)); CuAssertIntEquals(tc, 1, lighthouse_range(b, u2->faction, u2)); - test_cleanup(); + test_teardown(); } static void test_lighthouse_update(CuTest * tc) @@ -88,7 +88,7 @@ static void test_lighthouse_update(CuTest * tc) CuAssertPtrEquals(tc, (void *)&at_lighthouse, (void *)r2->attribs->type); CuAssertPtrNotNull(tc, r3->attribs); CuAssertPtrEquals(tc, (void *)&at_lighthouse, (void *)r3->attribs->type); - test_cleanup(); + test_teardown(); } CuSuite *get_lighthouse_suite(void) diff --git a/src/listbox.c b/src/listbox.c index 057240fad..afc04b232 100644 --- a/src/listbox.c +++ b/src/listbox.c @@ -8,8 +8,10 @@ * */ -/* wenn platform.h nicht vor curses included wird, kompiliert es unter windows nicht */ +#ifdef _MSC_VER #include +#endif + #include #include @@ -17,6 +19,7 @@ #include "gmtool_structs.h" #include +#include #include #include @@ -27,7 +30,7 @@ insert_selection(list_selection ** p_sel, list_selection * prev, const char *str, void *payload) { list_selection *sel = calloc(sizeof(list_selection), 1); - sel->str = strdup(str); + sel->str = str_strdup(str); sel->data = payload; if (*p_sel) { list_selection *s; diff --git a/src/magic.c b/src/magic.c index f83e31a7d..6855c307f 100644 --- a/src/magic.c +++ b/src/magic.c @@ -17,8 +17,9 @@ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. **/ +#ifdef _MSC_VER #include -#include +#endif #include "magic.h" #include "skill.h" @@ -41,6 +42,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include #include #include #include @@ -61,19 +63,21 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* util includes */ #include +#include +#include #include #include #include #include +#include #include -#include -#include #include +#include #include +#include #include -#include -#include +#include #include #include @@ -126,7 +130,7 @@ static double MagicPower(double force) if (force > 0) { const char *str = config_get("magic.power"); double value = str ? atof(str) : 1.0; - return MAX(value * force, 1.0f); + return fmax(value * force, 1.0f); } return 0; } @@ -141,6 +145,8 @@ static int a_readicastle(attrib * a, void *owner, struct gamedata *data) storage *store = data->store; icastle_data *idata = (icastle_data *)a->data.v; char token[32]; + + UNUSED_ARG(owner); READ_TOK(store, token, sizeof(token)); if (data->version < ATTRIBOWNER_VERSION) { READ_INT(store, NULL); @@ -213,7 +219,7 @@ extern int dice(int count, int value); /* ------------------------------------------------------------- */ /* aus dem alten System übriggebliegene Funktionen, die bei der * Umwandlung von alt nach neu gebraucht werden */ -/* ------------------------------------------------------------- */ + /* ------------------------------------------------------------- */ static void init_mage(attrib * a) { @@ -254,6 +260,7 @@ static int read_mage(attrib * a, void *owner, struct gamedata *data) sc_mage *mage = (sc_mage *)a->data.v; char spname[64]; + UNUSED_ARG(owner); READ_INT(store, &mtype); mage->magietyp = (magic_t)mtype; READ_INT(store, &mage->spellpoints); @@ -299,6 +306,7 @@ write_mage(const attrib * a, const void *owner, struct storage *store) int i; sc_mage *mage = (sc_mage *)a->data.v; + UNUSED_ARG(owner); WRITE_INT(store, mage->magietyp); WRITE_INT(store, mage->spellpoints); WRITE_INT(store, mage->spchange); @@ -360,6 +368,7 @@ static int read_seenspell(attrib * a, void *owner, struct gamedata *data) spell *sp = 0; char token[32]; + UNUSED_ARG(owner); READ_TOK(store, token, sizeof(token)); if (data->version < UNIQUE_SPELLS_VERSION) { READ_INT(store, 0); /* ignore mtype */ @@ -377,6 +386,7 @@ static void write_seenspell(const attrib * a, const void *owner, struct storage *store) { const spell *sp = (const spell *)a->data.v; + UNUSED_ARG(owner); WRITE_TOK(store, sp->sname); } @@ -448,7 +458,7 @@ void pick_random_spells(faction * f, int level, spellbook * book, int num_spells int maxspell = numspells; int spellno = -1; spellbook_entry *sbe = 0; - while (!sbe && maxspell>0) { + while (!sbe && maxspell > 0) { spellno = rng_int() % maxspell; sbe = commonspells[spellno]; if (sbe->level > f->max_spelllevel) { @@ -519,7 +529,10 @@ int get_combatspelllevel(const unit * u, int nr) assert(nr < MAXCOMBATSPELLS); if (m) { int level = effskill(u, SK_MAGIC, 0); - return MIN(m->combatspells[nr].level, level); + if (level < m->combatspells[nr].level) { + return level; + } + return m->combatspells[nr].level; } return -1; } @@ -651,9 +664,13 @@ int change_spellpoints(unit * u, int mp) } /* verhindere negative Magiepunkte */ - sp = MAX(m->spellpoints + mp, 0); - m->spellpoints = sp; - + sp = m->spellpoints + mp; + if (sp > 0) { + m->spellpoints = sp; + } + else { + m->spellpoints = 0; + } return sp; } @@ -678,10 +695,10 @@ static int get_spchange(const unit * u) * entstehen */ -/* Artefakt der Stärke - * Ermöglicht dem Magier mehr Magiepunkte zu 'speichern' - */ -/** TODO: at_skillmod daraus machen */ + /* Artefakt der Stärke + * Ermöglicht dem Magier mehr Magiepunkte zu 'speichern' + */ + /** TODO: at_skillmod daraus machen */ static int use_item_aura(const region * r, const unit * u) { int sk, n; @@ -711,7 +728,7 @@ int max_spellpoints(const region * r, const unit * u) if (n > 0) { msp = (msp * n) / 100; } - return MAX((int)msp, 0); + return (msp > 0) ? (int)msp : 0; } int change_maxspellpoints(unit * u, int csp) @@ -745,9 +762,7 @@ int countspells(unit * u, int step) count = m->spellcount + step; - /* negative Werte abfangen. */ - m->spellcount = MAX(0, count); - + m->spellcount = (count > 0) ? count : 0; return m->spellcount; } @@ -827,7 +842,7 @@ int eff_spelllevel(unit * u, const spell * sp, int cast_level, int range) } maxlevel = get_pooled(u, sp->components[k].type, GET_DEFAULT, - needplevel * cast_level) / needplevel; + needplevel * cast_level) / needplevel; /* sind die Kosten fix, so muss die Komponente nur einmal vorhanden * sein und der cast_level ändert sich nicht */ @@ -839,7 +854,9 @@ int eff_spelllevel(unit * u, const spell * sp, int cast_level, int range) } else if (sp->components[k].cost == SPC_LEVEL) { costtyp = SPC_LEVEL; - cast_level = MIN(cast_level, maxlevel); + if (maxlevel < cast_level) { + cast_level = maxlevel; + } /* bei Typ Linear müssen die Kosten in Höhe der Stufe vorhanden * sein, ansonsten schlägt der Spruch fehl */ } @@ -856,11 +873,13 @@ int eff_spelllevel(unit * u, const spell * sp, int cast_level, int range) spellbook * sb = unit_get_spellbook(u); if (sb) { spellbook_entry * sbe = spellbook_get(sb, sp); - if (sbe) { - return MIN(cast_level, sbe->level); + if (sbe && cast_level > sbe->level) { + return sbe->level; } } - log_error("spell %s is not in the spellbook for %s\n", sp->sname, unitname(u)); + else { + log_error("spell %s is not in the spellbook for %s\n", sp->sname, unitname(u)); + } } return cast_level; } @@ -904,7 +923,7 @@ void pay_spell(unit * u, const spell * sp, int cast_level, int range) */ bool knowsspell(const region * r, const unit * u, const spell * sp) { - /* Ist überhaupt ein gültiger Spruch angegeben? */ + UNUSED_ARG(r); assert(sp); /* steht der Spruch in der Spruchliste? */ return u_hasspell(u, sp) != 0; @@ -1073,7 +1092,7 @@ spellpower(region * r, unit * u, const spell * sp, int cast_level, struct order } } } - return MAX(force, 0); + return (force > 0) ? (int)force : 0; } /* ------------------------------------------------------------- */ @@ -1120,7 +1139,7 @@ variant magic_resistance(unit * target) bool bad_resist = true; if (rc == get_race(RC_HIRNTOETER) && !pl) { - prob = frac_mul(prob, frac_make(1, 2)); + prob = frac_mul(prob, frac_make(1, 2)); } assert(target->number > 0); /* Magier haben einen Resistenzbonus vom Magietalent * 5% */ @@ -1146,8 +1165,10 @@ variant magic_resistance(unit * target) /* Auswirkungen von Zaubern auf der Region */ a = a_find(target->region->attribs, &at_curse); while (a && a->type == &at_curse) { - curse *c = (curse *)a->data.v; - unit *mage = c->magician; + unit *mage; + + c = (curse *)a->data.v; + mage = c->magician; if (mage != NULL) { if (good_resist && c->type == &ct_goodmagicresistancezone) { @@ -1311,7 +1332,8 @@ bool fumble(region * r, unit * u, const spell * sp, int cast_grade) int fumble_enabled = config_get_int("magic.fumble.enable", 1); sc_mage * mage; - if (effsk<=0 || !fumble_enabled) { + UNUSED_ARG(sp); + if (effsk <= 0 || !fumble_enabled) { return false; } fumble_chance = (int)((cast_grade * 40.0 / (double)effsk) - 20.0); @@ -1366,10 +1388,10 @@ static void do_fumble(castorder * co) int level = co->level; int duration; double effect; - static const race *rc_toad; + static const race *rc_toad; static int rc_cache; fumble_f fun; - + ADDMSG(&u->faction->msgs, msg_message("patzer", "unit region spell", u, r, sp)); switch (rng_int() % 10) { @@ -1413,7 +1435,8 @@ static void do_fumble(castorder * co) case 2: /* temporary skill loss */ - duration = MAX(rng_int() % level / 2, 2); + duration = rng_int() % level / 2; + if (duration < 2) duration = 2; effect = level / -2.0; c = create_curse(u, &u->attribs, &ct_skillmod, level, duration, effect, 1); @@ -1519,16 +1542,18 @@ void regenerate_aura(void) * mindestens 1 Aura pro Monat */ regen = (int)reg_aura; reg_aura -= regen; - if (chance(reg_aura)) + if (chance(reg_aura)) { ++regen; - regen = MAX(1, regen); - regen = MIN((auramax - aura), regen); + } + if (regen < 1) regen = 1; + if (regen > auramax - aura) regen = auramax - aura; aura += regen; ADDMSG(&u->faction->msgs, msg_message("regenaura", "unit region amount", u, r, regen)); } - set_spellpoints(u, MIN(aura, auramax)); + if (aura > auramax) aura = auramax; + set_spellpoints(u, aura); } } } @@ -1536,7 +1561,7 @@ void regenerate_aura(void) static bool verify_ship(region * r, unit * mage, const spell * sp, spllprm * spobj, -order * ord) + order * ord) { ship *sh = findship(spobj->data.i); @@ -1559,7 +1584,7 @@ order * ord) static bool verify_building(region * r, unit * mage, const spell * sp, spllprm * spobj, -order * ord) + order * ord) { building *b = findbuilding(spobj->data.i); @@ -1602,7 +1627,7 @@ message *msg_unitnotfound(const struct unit * mage, struct order * ord, static bool verify_unit(region * r, unit * mage, const spell * sp, spllprm * spobj, -order * ord) + order * ord) { unit *u = NULL; switch (spobj->typ) { @@ -1648,8 +1673,8 @@ order * ord) * Sichtbarkeit. Dabei zählen wir die magieresistenten (resists) * Objekte. Alle anderen werten wir als Erfolge (success) */ -/* gibt bei Misserfolg 0 zurück, bei Magieresistenz zumindeste eines - * Objektes 1 und bei Erfolg auf ganzer Linie 2 */ + /* gibt bei Misserfolg 0 zurück, bei Magieresistenz zumindeste eines + * Objektes 1 und bei Erfolg auf ganzer Linie 2 */ static void verify_targets(castorder * co, int *invalid, int *resist, int *success) { @@ -1845,7 +1870,7 @@ static int addparam_string(const char *const param[], spllprm ** spobjp) spobj->flag = 0; spobj->typ = SPP_STRING; - spobj->data.xs = strdup(param[0]); + spobj->data.xs = str_strdup(param[0]); return 1; } @@ -1884,7 +1909,7 @@ static int addparam_building(const char *const param[], spllprm ** spobjp) static int addparam_region(const char *const param[], spllprm ** spobjp, const unit * u, -order * ord) + order * ord) { assert(param[0]); if (param[1] == 0) { @@ -1920,7 +1945,7 @@ order * ord) static int addparam_unit(const char *const param[], spllprm ** spobjp, const unit * u, -order * ord) + order * ord) { spllprm *spobj; int i = 0; @@ -2156,6 +2181,7 @@ static void a_write_unit(const attrib * a, const void *owner, struct storage *store) { unit *u = (unit *)a->data.v; + UNUSED_ARG(owner); write_unit_reference(u, store); } @@ -2258,6 +2284,7 @@ void create_newfamiliar(unit * mage, unit * fam) } static void * resolve_familiar(int id, void *data) { + UNUSED_ARG(id); if (data) { unit *familiar = (unit *)data; attrib *a = a_find(familiar->attribs, &at_familiarmage); @@ -2271,6 +2298,7 @@ static void * resolve_familiar(int id, void *data) { static int read_familiar(attrib * a, void *owner, struct gamedata *data) { + UNUSED_ARG(owner); if (read_unit_reference(data, (unit **)&a->data.v, resolve_familiar) <= 0) { return AT_READ_FAIL; } @@ -2303,7 +2331,7 @@ void create_newclone(unit * mage, unit * clone) /* Wenn der Magier stirbt, wird das in destroy_unit abgefangen. * Kein Trigger, zu kompliziert. */ - /* Wenn der Klon stirbt, dann bekommt der Magier einen Schock */ + /* Wenn der Klon stirbt, dann bekommt der Magier einen Schock */ add_trigger(&clone->attribs, "destroy", trigger_clonedied(mage)); } @@ -2337,6 +2365,7 @@ unit *has_clone(unit * mage) } static void * resolve_clone(int id, void *data) { + UNUSED_ARG(id); if (data) { unit *clone = (unit *)data; attrib *a = a_find(clone->attribs, &at_clonemage); @@ -2350,6 +2379,7 @@ static void * resolve_clone(int id, void *data) { static int read_clone(attrib * a, void *owner, struct gamedata *data) { + UNUSED_ARG(owner); if (read_unit_reference(data, (unit **)&a->data.v, resolve_clone) <= 0) { return AT_READ_FAIL; } @@ -2358,6 +2388,7 @@ static int read_clone(attrib * a, void *owner, struct gamedata *data) /* mages */ static void * resolve_mage(int id, void *data) { + UNUSED_ARG(id); if (data) { unit *mage = (unit *)data; attrib *a = a_find(mage->attribs, &at_familiar); @@ -2371,6 +2402,7 @@ static void * resolve_mage(int id, void *data) { static int read_magician(attrib * a, void *owner, struct gamedata *data) { + UNUSED_ARG(owner); if (read_unit_reference(data, (unit **)&a->data.v, resolve_mage) <= 0) { return AT_READ_FAIL; } @@ -2433,9 +2465,9 @@ unit *get_familiar(const unit * u) { attrib *a = a_find(u->attribs, &at_familiar); if (a != NULL) { - unit *u = (unit *)a->data.v; - if (u->number > 0) - return u; + unit *uf = (unit *)a->data.v; + if (uf->number > 0) + return uf; } return NULL; } @@ -2444,9 +2476,9 @@ unit *get_familiar_mage(const unit * u) { attrib *a = a_find(u->attribs, &at_familiarmage); if (a != NULL) { - unit *u = (unit *)a->data.v; - if (u->number > 0) - return u; + unit *um = (unit *)a->data.v; + if (um->number > 0) + return um; } return NULL; } @@ -2455,9 +2487,9 @@ unit *get_clone(const unit * u) { attrib *a = a_find(u->attribs, &at_clone); if (a != NULL) { - unit *u = (unit *)a->data.v; - if (u->number > 0) - return u; + unit *uc = (unit *)a->data.v; + if (uc->number > 0) + return uc; } return NULL; } @@ -2466,14 +2498,14 @@ unit *get_clone_mage(const unit * u) { attrib *a = a_find(u->attribs, &at_clonemage); if (a != NULL) { - unit *u = (unit *)a->data.v; - if (u->number > 0) - return u; + unit *um = (unit *)a->data.v; + if (um->number > 0) + return um; } return NULL; } -static bool is_moving_ship(const region * r, ship * sh) +static bool is_moving_ship(ship * sh) { const unit *u = ship_owner(sh); @@ -2485,7 +2517,7 @@ static bool is_moving_ship(const region * r, ship * sh) return true; default: return false; - } + } return false; } @@ -2507,20 +2539,20 @@ static castorder *cast_cmd(unit * u, order * ord) cmistake(u, ord, 224, MSG_MAGIC); return 0; } - pl = rplane(r); + pl = getplane(r); if (pl && fval(pl, PFL_NOMAGIC)) { cmistake(u, ord, 269, MSG_MAGIC); return 0; } level = effskill(u, SK_MAGIC, 0); - init_order(ord); + init_order_depr(ord); s = gettoken(token, sizeof(token)); param = findparam(s, u->faction->locale); /* für Syntax ' STUFE x REGION y z ' */ if (param == P_LEVEL) { int p = getint(); - level = MIN(p, level); + if (level > p) level = p; if (level < 1) { /* Fehler "Das macht wenig Sinn" */ syntax_error(u, ord); @@ -2532,7 +2564,7 @@ static castorder *cast_cmd(unit * u, order * ord) if (param == P_REGION) { int t_x = getint(); int t_y = getint(); - plane *pl = getplane(u->region); + t_x = rel_to_abs(pl, u->faction, t_x, 0); t_y = rel_to_abs(pl, u->faction, t_y, 1); pnormalize(&t_x, &t_y, pl); @@ -2550,7 +2582,7 @@ static castorder *cast_cmd(unit * u, order * ord) * hier nach REGION nochmal auf STUFE prüfen */ if (param == P_LEVEL) { int p = getint(); - level = MIN(p, level); + if (level > p) level = p; if (level < 1) { /* Fehler "Das macht wenig Sinn" */ syntax_error(u, ord); @@ -2569,7 +2601,7 @@ static castorder *cast_cmd(unit * u, order * ord) /* Vertraute können auch Zauber sprechen, die sie selbst nicht * können. unit_getspell findet aber nur jene Sprüche, die * die Einheit beherrscht. */ - if (!sp && is_familiar(u)) { + if (!sp && is_familiar(u)) { caster = get_familiar_mage(u); if (caster) { familiar = u; @@ -2619,7 +2651,7 @@ static castorder *cast_cmd(unit * u, order * ord) * ONSHIPCAST deklarierte Zauber sprechen */ } else if (u->ship) { - if (is_moving_ship(r, u->ship)) { + if (is_moving_ship(u->ship)) { if (!(sp->sptyp & ONSHIPCAST)) { /* Fehler: "Diesen Spruch kann man nicht auf einem sich * bewegenden Schiff stehend zaubern" */ @@ -2666,12 +2698,14 @@ static castorder *cast_cmd(unit * u, order * ord) return 0; } if (caster != familiar) { /* Magier zaubert durch Vertrauten */ + int sk; if (range > 1) { /* Fehler! Versucht zu Farcasten */ ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "familiar_farcast", "mage", caster)); return 0; } - if (distance(caster->region, r) > effskill(caster, SK_MAGIC, 0)) { + sk = effskill(caster, SK_MAGIC, 0); + if (distance(caster->region, r) > sk) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "familiar_toofar", "mage", caster)); return 0; @@ -2681,7 +2715,8 @@ static castorder *cast_cmd(unit * u, order * ord) * löschen, zaubern kann er noch */ range *= 2; set_order(&caster->thisorder, NULL); - level = MIN(level, effskill(caster, SK_MAGIC, 0) / 2); + sk /= 2; + if (level > sk) level = sk; } } /* Weitere Argumente zusammenbasteln */ @@ -2704,7 +2739,7 @@ static castorder *cast_cmd(unit * u, order * ord) break; } } - params[p++] = strdup(s); + params[p++] = str_strdup(s); } params[p] = 0; args = @@ -2744,7 +2779,6 @@ void magic(void) { region *r; int rank; - castorder *co; spellrank spellranks[MAX_SPELLRANK]; const race *rc_insect = get_race(RC_INSECT); @@ -2787,6 +2821,7 @@ void magic(void) * Spruch gezaubert wird) */ for (rank = 0; rank < MAX_SPELLRANK; rank++) { + castorder *co; for (co = spellranks[rank].begin; co; co = co->next) { order *ord = co->order; int invalid, resist, success, cast_level = co->level; @@ -3000,7 +3035,7 @@ spellbook * get_spellbook(const char * name) const void * match; if (len >= SBNAMELEN) { - log_error("spellbook name is longer than %d bytes: %s", SBNAMELEN-1, name); + log_error("spellbook name is longer than %d bytes: %s", SBNAMELEN - 1, name); return NULL; } @@ -3026,6 +3061,9 @@ void free_spellbook(spellbook *sb) { static int free_spellbook_cb(const void *match, const void *key, size_t keylen, void *data) { const sb_entry *ent = (const sb_entry *)match; + UNUSED_ARG(data); + UNUSED_ARG(keylen); + UNUSED_ARG(key); free_spellbook(ent->value); return 0; } diff --git a/src/magic.test.c b/src/magic.test.c index a10c02b7b..f4606b75a 100644 --- a/src/magic.test.c +++ b/src/magic.test.c @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -35,7 +36,7 @@ void test_updatespells(CuTest * tc) test_setup(); test_create_race("human"); - f = test_create_faction(0); + f = test_create_faction(NULL); sp = create_spell("testspell"); CuAssertPtrNotNull(tc, sp); @@ -49,7 +50,7 @@ void test_updatespells(CuTest * tc) CuAssertIntEquals(tc, 1, selist_length(f->spellbook->spells)); CuAssertPtrNotNull(tc, spellbook_get(f->spellbook, sp)); free_spellbook(book); - test_cleanup(); + test_teardown(); } static void test_get_spellbook(CuTest * tc) @@ -60,7 +61,7 @@ static void test_get_spellbook(CuTest * tc) CuAssertPtrNotNull(tc, sb = get_spellbook("hodorhodorhodor")); CuAssertPtrEquals(tc, sb, get_spellbook("hodorhodorhodor")); CuAssertTrue(tc, sb != get_spellbook("hodor")); - test_cleanup(); + test_teardown(); } static void test_spellbooks(CuTest * tc) @@ -87,10 +88,13 @@ static void test_spellbooks(CuTest * tc) CuAssertPtrNotNull(tc, entry); CuAssertPtrEquals(tc, sp, entry->sp); - test_cleanup(); + test_teardown(); + test_setup(); + herp = get_spellbook("herp"); CuAssertPtrNotNull(tc, herp); - test_cleanup(); + + test_teardown(); } void test_pay_spell(CuTest * tc) @@ -104,7 +108,7 @@ void test_pay_spell(CuTest * tc) test_setup(); init_resources(); r = test_create_region(0, 0, NULL); - f = test_create_faction(0); + f = test_create_faction(NULL); u = test_create_unit(f, r); CuAssertPtrNotNull(tc, u); @@ -124,7 +128,7 @@ void test_pay_spell(CuTest * tc) CuAssertIntEquals(tc, 0, get_resource(u, get_resourcetype(R_SILVER))); CuAssertIntEquals(tc, 0, get_resource(u, get_resourcetype(R_AURA))); CuAssertIntEquals(tc, 0, get_resource(u, get_resourcetype(R_HORSE))); - test_cleanup(); + test_teardown(); } void test_pay_spell_failure(CuTest * tc) @@ -138,7 +142,7 @@ void test_pay_spell_failure(CuTest * tc) test_setup(); init_resources(); r = test_create_region(0, 0, NULL); - f = test_create_faction(0); + f = test_create_faction(NULL); u = test_create_unit(f, r); CuAssertPtrNotNull(tc, u); @@ -162,7 +166,7 @@ void test_pay_spell_failure(CuTest * tc) CuAssertIntEquals(tc, 0, eff_spelllevel(u, sp, 3, 1)); CuAssertIntEquals(tc, 0, change_resource(u, get_resourcetype(R_SILVER), -1)); CuAssertIntEquals(tc, 0, eff_spelllevel(u, sp, 2, 1)); - test_cleanup(); + test_teardown(); } void test_getspell_unit(CuTest * tc) @@ -174,8 +178,8 @@ void test_getspell_unit(CuTest * tc) struct locale * lang; test_setup(); - r = test_create_region(0, 0, 0); - f = test_create_faction(0); + r = test_create_region(0, 0, NULL); + f = test_create_faction(NULL); u = test_create_unit(f, r); create_mage(u, M_GRAY); enable_skill(SK_MAGIC, true); @@ -190,7 +194,7 @@ void test_getspell_unit(CuTest * tc) unit_add_spell(u, 0, sp, 1); CuAssertPtrNotNull(tc, unit_getspell(u, "Herp-a-derp", lang)); - test_cleanup(); + test_teardown(); } void test_getspell_faction(CuTest * tc) @@ -203,7 +207,7 @@ void test_getspell_faction(CuTest * tc) test_setup(); r = test_create_region(0, 0, NULL); - f = test_create_faction(0); + f = test_create_faction(NULL); f->magiegebiet = M_TYBIED; u = test_create_unit(f, r); create_mage(u, f->magiegebiet); @@ -220,7 +224,7 @@ void test_getspell_faction(CuTest * tc) f->spellbook = create_spellbook(0); spellbook_add(f->spellbook, sp, 1); CuAssertPtrEquals(tc, sp, unit_getspell(u, "Herp-a-derp", lang)); - test_cleanup(); + test_teardown(); } void test_getspell_school(CuTest * tc) @@ -234,7 +238,7 @@ void test_getspell_school(CuTest * tc) test_setup(); r = test_create_region(0, 0, NULL); - f = test_create_faction(0); + f = test_create_faction(NULL); f->magiegebiet = M_TYBIED; u = test_create_unit(f, r); create_mage(u, f->magiegebiet); @@ -251,7 +255,7 @@ void test_getspell_school(CuTest * tc) CuAssertPtrNotNull(tc, book); spellbook_add(book, sp, 1); CuAssertPtrEquals(tc, sp, unit_getspell(u, "Herp-a-derp", lang)); - test_cleanup(); + test_teardown(); } void test_set_pre_combatspell(CuTest * tc) @@ -264,7 +268,7 @@ void test_set_pre_combatspell(CuTest * tc) test_setup(); r = test_create_region(0, 0, NULL); - f = test_create_faction(0); + f = test_create_faction(NULL); f->magiegebiet = M_TYBIED; u = test_create_unit(f, r); enable_skill(SK_MAGIC, true); @@ -283,7 +287,7 @@ void test_set_pre_combatspell(CuTest * tc) unset_combatspell(u, sp); CuAssertIntEquals(tc, 0, get_combatspelllevel(u, index)); CuAssertPtrEquals(tc, 0, (spell *)get_combatspell(u, index)); - test_cleanup(); + test_teardown(); } void test_set_main_combatspell(CuTest * tc) @@ -296,7 +300,7 @@ void test_set_main_combatspell(CuTest * tc) test_setup(); r = test_create_region(0, 0, NULL); - f = test_create_faction(0); + f = test_create_faction(NULL); f->magiegebiet = M_TYBIED; u = test_create_unit(f, r); enable_skill(SK_MAGIC, true); @@ -315,7 +319,7 @@ void test_set_main_combatspell(CuTest * tc) unset_combatspell(u, sp); CuAssertIntEquals(tc, 0, get_combatspelllevel(u, index)); CuAssertPtrEquals(tc, 0, (spell *)get_combatspell(u, index)); - test_cleanup(); + test_teardown(); } void test_set_post_combatspell(CuTest * tc) @@ -328,7 +332,7 @@ void test_set_post_combatspell(CuTest * tc) test_setup(); r = test_create_region(0, 0, NULL); - f = test_create_faction(0); + f = test_create_faction(NULL); f->magiegebiet = M_TYBIED; u = test_create_unit(f, r); enable_skill(SK_MAGIC, true); @@ -347,7 +351,7 @@ void test_set_post_combatspell(CuTest * tc) unset_combatspell(u, sp); CuAssertIntEquals(tc, 0, get_combatspelllevel(u, index)); CuAssertPtrEquals(tc, 0, (spell *)get_combatspell(u, index)); - test_cleanup(); + test_teardown(); } void test_hasspell(CuTest * tc) @@ -359,7 +363,7 @@ void test_hasspell(CuTest * tc) test_setup(); r = test_create_region(0, 0, NULL); - f = test_create_faction(0); + f = test_create_faction(NULL); f->magiegebiet = M_TYBIED; u = test_create_unit(f, r); enable_skill(SK_MAGIC, true); @@ -376,7 +380,7 @@ void test_hasspell(CuTest * tc) set_level(u, SK_MAGIC, 1); CuAssertTrue(tc, !u_hasspell(u, sp)); - test_cleanup(); + test_teardown(); } static selist * casts; @@ -400,7 +404,7 @@ void test_multi_cast(CuTest *tc) { locale_setstring(lang, mkname("spell", sp->sname), "Feuerball"); CuAssertStrEquals(tc, "Feuerball", spell_name(sp, lang)); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); set_level(u, SK_MAGIC, 10); unit_add_spell(u, 0, sp, 1); CuAssertPtrEquals(tc, sp, unit_getspell(u, "Feuerball", lang)); @@ -412,7 +416,7 @@ void test_multi_cast(CuTest *tc) { CuAssertPtrNotNull(tc, casts); CuAssertIntEquals(tc, 2, selist_length(casts)); selist_free(casts); - test_cleanup(); + test_teardown(); } static void test_magic_resistance(CuTest *tc) { @@ -421,7 +425,7 @@ static void test_magic_resistance(CuTest *tc) { test_setup(); rc = test_create_race("human"); - u = test_create_unit(test_create_faction(rc), test_create_region(0, 0, 0)); + u = test_create_unit(test_create_faction(rc), test_create_region(0, 0, NULL)); CuAssertTrue(tc, frac_equal(rc->magres, magic_resistance(u))); rc->magres = frac_one; CuAssert(tc, "magic resistance is capped at 0.9", frac_equal(magic_resistance(u), frac_make(9, 10))); @@ -431,7 +435,7 @@ static void test_magic_resistance(CuTest *tc) { CuAssert(tc, "brain eaters outside astral space have 50% magres", frac_equal(magic_resistance(u), frac_make(1, 2))); u->region->_plane = get_astralplane(); CuAssert(tc, "brain eaters in astral space have full magres", frac_equal(magic_resistance(u), frac_make(9, 10))); - test_cleanup(); + test_teardown(); } static void test_max_spellpoints(CuTest *tc) { @@ -440,7 +444,7 @@ static void test_max_spellpoints(CuTest *tc) { test_setup(); rc = test_create_race("human"); - u = test_create_unit(test_create_faction(rc), test_create_region(0, 0, 0)); + u = test_create_unit(test_create_faction(rc), test_create_region(0, 0, NULL)); CuAssertIntEquals(tc, 1, max_spellpoints(u->region, u)); rc->maxaura = 100; CuAssertIntEquals(tc, 1, max_spellpoints(u->region, u)); @@ -454,7 +458,7 @@ static void test_max_spellpoints(CuTest *tc) { /* permanent aura loss: */ CuAssertIntEquals(tc, 7, change_maxspellpoints(u, -2)); CuAssertIntEquals(tc, 7, max_spellpoints(u->region, u)); - test_cleanup(); + test_teardown(); } static void test_illusioncastle(CuTest *tc) @@ -473,9 +477,9 @@ static void test_illusioncastle(CuTest *tc) CuAssertPtrEquals(tc, btype, (void *)icastle_type(a)); CuAssertPtrEquals(tc, bt_icastle, (void *)b->type); CuAssertStrEquals(tc, "castle", buildingtype(btype, b, b->size)); - btype->construction->name = strdup("site"); + btype->construction->name = str_strdup("site"); CuAssertStrEquals(tc, "site", buildingtype(btype, b, b->size)); - test_cleanup(); + test_teardown(); } static void test_is_mage(CuTest *tc) { @@ -483,7 +487,7 @@ static void test_is_mage(CuTest *tc) { sc_mage *mage; test_setup(); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); CuAssertPtrEquals(tc, NULL, get_mage(u)); CuAssertTrue(tc, !is_mage(u)); set_level(u, SK_MAGIC, 1); @@ -492,7 +496,7 @@ static void test_is_mage(CuTest *tc) { CuAssertPtrNotNull(tc, mage = create_mage(u, M_CERDDOR)); CuAssertPtrEquals(tc, mage, get_mage(u)); CuAssertTrue(tc, is_mage(u)); - test_cleanup(); + test_teardown(); } static void test_get_mage(CuTest *tc) { @@ -500,7 +504,7 @@ static void test_get_mage(CuTest *tc) { sc_mage *mage; test_setup(); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); CuAssertPtrEquals(tc, NULL, get_mage(u)); CuAssertPtrEquals(tc, NULL, get_mage_depr(u)); CuAssertPtrNotNull(tc, mage = create_mage(u, M_CERDDOR)); @@ -509,7 +513,7 @@ static void test_get_mage(CuTest *tc) { set_level(u, SK_MAGIC, 1); CuAssertPtrEquals(tc, mage, get_mage(u)); CuAssertPtrEquals(tc, mage, get_mage_depr(u)); - test_cleanup(); + test_teardown(); } static void test_familiar_set(CuTest *tc) { @@ -517,8 +521,8 @@ static void test_familiar_set(CuTest *tc) { test_setup(); - mag = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); - fam = test_create_unit(mag->faction, test_create_region(0, 0, 0)); + mag = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); + fam = test_create_unit(mag->faction, test_create_region(0, 0, NULL)); CuAssertPtrEquals(tc, NULL, get_familiar(mag)); CuAssertPtrEquals(tc, NULL, get_familiar_mage(fam)); CuAssertPtrEquals(tc, NULL, a_find(mag->attribs, &at_skillmod)); @@ -529,7 +533,7 @@ static void test_familiar_set(CuTest *tc) { remove_familiar(mag); CuAssertPtrEquals(tc, NULL, get_familiar(mag)); CuAssertPtrEquals(tc, NULL, a_find(mag->attribs, &at_skillmod)); - test_cleanup(); + test_teardown(); } static void test_familiar_age(CuTest *tc) { @@ -537,8 +541,8 @@ static void test_familiar_age(CuTest *tc) { test_setup(); - mag = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); - fam = test_create_unit(mag->faction, test_create_region(0, 0, 0)); + mag = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); + fam = test_create_unit(mag->faction, test_create_region(0, 0, NULL)); set_familiar(mag, fam); CuAssertPtrEquals(tc, fam, get_familiar(mag)); CuAssertPtrEquals(tc, mag, get_familiar_mage(fam)); @@ -549,7 +553,7 @@ static void test_familiar_age(CuTest *tc) { set_number(fam, 0); a_age(&mag->attribs, mag); CuAssertPtrEquals(tc, NULL, get_familiar(mag)); - test_cleanup(); + test_teardown(); } static void test_familiar_equip(CuTest *tc) { @@ -571,8 +575,8 @@ static void test_familiar_equip(CuTest *tc) { equipment_setskill(eq, SK_ENTERTAINMENT, "5"); equipment_addspell(eq, sp->sname, 1); - mag = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); - u = test_create_unit(mag->faction, test_create_region(0, 0, 0)); + mag = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); + u = test_create_unit(mag->faction, test_create_region(0, 0, NULL)); set_familiar(mag, u); create_newfamiliar(mag, u); CuAssertIntEquals(tc, 1, i_get(u->items, itype)); @@ -586,7 +590,7 @@ static void test_familiar_equip(CuTest *tc) { CuAssertPtrEquals(tc, mage, get_mage_depr(u)); CuAssertTrue(tc, u_hasspell(u, sp)); - test_cleanup(); + test_teardown(); } CuSuite *get_familiar_suite(void) diff --git a/src/main.c b/src/main.c index eedb25cf1..f50f65472 100644 --- a/src/main.c +++ b/src/main.c @@ -16,14 +16,22 @@ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. **/ +#ifdef _MSC_VER #include -#include +#endif #include -#include +#include +#include #include +#include + #include #include +#include +#include +#include + #include "eressea.h" #ifdef USE_CURSES #include "gmtool.h" @@ -62,7 +70,6 @@ static void load_inifile(void) set_datapath(str); } - lomem = config_get_int("game.lomem", lomem) ? 1 : 0; verbosity = config_get_int("game.verbose", 2); memdebug = config_get_int("game.memcheck", memdebug); #ifdef USE_CURSES @@ -79,12 +86,13 @@ static const char * valid_keys[] = { "game.locale", "game.verbose", "game.report", - "game.lomem", "game.memcheck", "game.email", "game.mailcmd", "game.era", "game.sender", + "game.dbname", + "game.dbbatch", "editor.color", "editor.codepage", "editor.population.", @@ -94,17 +102,18 @@ static const char * valid_keys[] = { static dictionary *parse_config(const char *filename) { - char path[MAX_PATH]; + char path[PATH_MAX]; dictionary *d; const char *str, *cfgpath = config_get("config.path"); if (cfgpath) { - join_path(cfgpath, filename, path, sizeof(path)); + path_join(cfgpath, filename, path, sizeof(path)); log_debug("reading from configuration file %s\n", path); - d = iniparser_load(path); - } else { + d = iniparser_load(path); + } + else { log_debug("reading from configuration file %s\n", filename); - d = iniparser_load(filename); + d = iniparser_load(filename); } if (d) { config_set_from(d, valid_keys); @@ -168,8 +177,7 @@ static int verbosity_to_flags(int verbosity) { static int parse_args(int argc, char **argv) { int i; - int log_stderr = LOG_CPERROR; - int log_flags = LOG_CPERROR | LOG_CPWARNING | LOG_CPINFO; + int log_stderr, log_flags = 2; for (i = 1; i != argc; ++i) { char *argi = argv[i]; @@ -179,9 +187,9 @@ static int parse_args(int argc, char **argv) else if (argi[1] == '-') { /* long format */ if (strcmp(argi + 2, "version") == 0) { printf("Eressea version %s, " - "Copyright (C) 2017 Enno Rehling et al.\n", + "Copyright (C) 2017 Enno Rehling et al.\n", eressea_version()); - return 1; + return 1; #ifdef USE_CURSES } else if (strcmp(argi + 2, "color") == 0) { @@ -298,10 +306,11 @@ int main(int argc, char **argv) lua_State *L; dictionary *d = 0; setup_signal_handler(); + message_handle_missing(MESSAGE_MISSING_REPLACE); /* parse arguments again, to override ini file */ err = parse_args(argc, argv); - if (err!=0) { - return (err>0) ? 0 : err; + if (err != 0) { + return (err > 0) ? 0 : err; } d = parse_config(inifile); if (!d) { diff --git a/src/market.c b/src/market.c index 8fd4e3f0d..fd62ae353 100644 --- a/src/market.c +++ b/src/market.c @@ -71,7 +71,7 @@ attrib_type at_market = { bool markets_module(void) { - return (bool)config_get_int("modules.markets", 0); + return (bool)config_get_int("modules.market", 0); } void do_markets(void) diff --git a/src/market.test.c b/src/market.test.c index 2beeaea6b..1fc8307fa 100644 --- a/src/market.test.c +++ b/src/market.test.c @@ -12,6 +12,7 @@ #include #include +#include #include #include @@ -32,6 +33,7 @@ static void test_market_curse(CuTest * tc) building_type *btype; test_setup(); + mt_register(mt_new_va("buyamount", "unit:unit", "amount:int", "resource:resource", NULL)); htype = test_create_itemtype("herb"); htype->flags |= ITF_HERB; @@ -66,7 +68,7 @@ static void test_market_curse(CuTest * tc) b->flags |= BLD_MAINTAINED; b->size = b->type->maxsize; - f = test_create_faction(0); + f = test_create_faction(NULL); u = test_create_unit(f, r); u_set_building(u, b); @@ -74,7 +76,7 @@ static void test_market_curse(CuTest * tc) CuAssertIntEquals(tc, 70, i_get(u->items, htype)); CuAssertIntEquals(tc, 35, i_get(u->items, ltype)); - test_cleanup(); + test_teardown(); } static void test_rc_trade(CuTest *tc) { @@ -87,7 +89,7 @@ static void test_rc_trade(CuTest *tc) { rc_set_param(rc, "herb_trade", "50"); CuAssertIntEquals(tc, 100, rc_luxury_trade(rc)); CuAssertIntEquals(tc, 50, rc_herb_trade(rc)); - test_cleanup(); + test_teardown(); } CuSuite *get_market_suite(void) diff --git a/src/modules/CMakeLists.txt b/src/modules/CMakeLists.txt index 82dee9ec4..5b98897d4 100644 --- a/src/modules/CMakeLists.txt +++ b/src/modules/CMakeLists.txt @@ -4,7 +4,6 @@ autoseed.c gmcmd.c museum.c score.c -weather.c xmas.c ) FOREACH(_FILE ${_FILES}) diff --git a/src/modules/autoseed.c b/src/modules/autoseed.c index 52a5344cc..17ea1084f 100644 --- a/src/modules/autoseed.c +++ b/src/modules/autoseed.c @@ -33,13 +33,13 @@ /* util includes */ #include #include -#include #include #include #include #include #include #include +#include #include /* libc includes */ @@ -155,7 +155,7 @@ newfaction *read_newfactions(const char *filename) email[0] = '\0'; password[0] = '\0'; - if (sscanf(buf, "%54s %20s %8s %16s %d %d", email, race, lang, + if (sscanf(buf, "%54s %19s %7s %15s %4d %4d", email, race, lang, password, &subscription, &alliance) < 3) { break; } @@ -166,12 +166,10 @@ newfaction *read_newfactions(const char *filename) break; } if (password[0] == '\0') { - size_t sz; - sz = strlcpy(password, itoa36(rng_int()), sizeof(password)); - sz += strlcat(password, itoa36(rng_int()), sizeof(password)); + snprintf(password, sizeof(password), "%s%s", itoa36(rng_int()), itoa36(rng_int())); } for (f = factions; f; f = f->next) { - if (strcmp(f->email, email) == 0 && f->age < MINAGE_MULTI) { + if (strcmp(faction_getemail(f), email) == 0 && f->age < MINAGE_MULTI) { log_warning("email %s already in use by %s", email, factionname(f)); break; } @@ -188,12 +186,14 @@ newfaction *read_newfactions(const char *filename) continue; } nf = calloc(sizeof(newfaction), 1); - if (set_email(&nf->email, email) != 0) { + if (check_email(email) == 0) { + nf->email = str_strdup(email); + } else { log_error("Invalid email address for subscription %s: %s\n", itoa36(subscription), email); free(nf); continue; } - nf->password = strdup(password); + nf->password = str_strdup(password); nf->race = rc_find(race); nf->subscription = subscription; if (alliances != NULL) { @@ -619,6 +619,7 @@ int autoseed(newfaction ** players, int nsize, int max_agediff) while (*nfp) { newfaction *nf = *nfp; if (strcmp(nextf->email, nf->email) == 0) { + log_warning("Duplicate email %s\n", nf->email?nf->email:""); *nfp = nf->next; free_newfaction(nf); } @@ -960,8 +961,8 @@ int build_island_e3(int x, int y, int minsize, newfaction ** players, int numfac q = region_quality(r, rn); if (q >= MIN_QUALITY && nfactions < numfactions && players && *players) { starting_region(players, r, rn); - minq = MIN(minq, q); - maxq = MAX(maxq, q); + if (minq > q) minq = q; + if (maxq < q) maxq = q; ++nfactions; } } @@ -975,8 +976,8 @@ int build_island_e3(int x, int y, int minsize, newfaction ** players, int numfac q = region_quality(r, rn); if (q >= MIN_QUALITY * 4 / 3 && nfactions < numfactions && players && *players) { starting_region(players, r, rn); - minq = MIN(minq, q); - maxq = MAX(maxq, q); + if (minq > q) minq = q; + if (maxq < q) maxq = q; ++nfactions; } } diff --git a/src/modules/museum.c b/src/modules/museum.c index 1eee3529f..0f9fe9923 100644 --- a/src/modules/museum.c +++ b/src/modules/museum.c @@ -20,7 +20,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include -#if MUSEUM_MODULE #include "museum.h" /* kernel includes */ @@ -45,6 +44,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include #include @@ -460,7 +460,7 @@ static void use_key1(connection *b, void *data) { if (b->type == &bt_questportal) { const struct item_type *itype = it_find("questkey1"); ADDMSG(&u->faction->msgs, - msg_message("use_item", "unit item", u, itype->rtype)); + msg_message("use_item", "unit amount item", u, 1, itype->rtype)); b->data.i &= 0xFE; } } @@ -470,7 +470,7 @@ static void use_key2(connection *b, void *data) { if (b->type == &bt_questportal) { const struct item_type *itype = it_find("questkey2"); ADDMSG(&u->faction->msgs, - msg_message("use_item", "unit item", u, itype->rtype)); + msg_message("use_item", "unit amount item", u, 1, itype->rtype)); b->data.i &= 0xFD; } } @@ -502,5 +502,3 @@ void register_museum(void) register_item_use(use_museumkey, "use_questkey1"); register_item_use(use_museumkey, "use_questkey2"); } - -#endif diff --git a/src/modules/museum.h b/src/modules/museum.h index ed9dc74b0..704d38604 100644 --- a/src/modules/museum.h +++ b/src/modules/museum.h @@ -20,10 +20,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #define HEADER_MUSEUM_H #ifdef __cplusplus extern "C" { -#endif - -#if MUSEUM_MODULE == 0 -#error "must define MUSEUM_MODULE to use this module" #endif extern struct attrib_type at_warden; diff --git a/src/modules/score.c b/src/modules/score.c index efb3465d4..7b6cb07bb 100644 --- a/src/modules/score.c +++ b/src/modules/score.c @@ -34,8 +34,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* util includes */ #include -#include #include +#include /* libc includes */ #include @@ -153,7 +153,7 @@ void score(void) allscores = 1; } - join_path(basepath(), "score", path, sizeof(path)); + path_join(basepath(), "score", path, sizeof(path)); scoreFP = fopen(path, "w"); if (scoreFP) { const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf, 0 }; @@ -178,7 +178,7 @@ void score(void) alliance *a; const item_type *token = it_find("conquesttoken"); - join_path(basepath(), "score.alliances", path, sizeof(path)); + path_join(basepath(), "score.alliances", path, sizeof(path)); scoreFP = fopen(path, "w"); if (scoreFP) { const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf, 0 }; @@ -237,5 +237,5 @@ int default_score(const item_type *itype) { } void write_score(char *buffer, size_t size, score_t score) { - slprintf(buffer, size, "%lld", score); + snprintf(buffer, size, "%lld", score); } diff --git a/src/modules/weather.c b/src/modules/weather.c deleted file mode 100644 index ef71197b0..000000000 --- a/src/modules/weather.c +++ /dev/null @@ -1,132 +0,0 @@ -/* -Copyright (c) 1998-2015, Enno Rehling -Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifdef WEATHER - -#include -#include -#include "weather.h" - -/* libc includes */ -#include - -weather *create_weather(region * r, weather_t type) -{ - weather *w; - - w = calloc(1, sizeof(weather)); - w->center[0] = r->x; - w->center[1] = r->y; - w->type = type; - w->move[0] = (rng_int() % 3) - 1; - w->move[1] = (rng_int() % 3) - 1; - - switch (type) { - case WEATHER_STORM: - w->radius = rng_int() % 2 + 1; - break; - case WEATHER_HURRICANE: - w->radius = 1; - break; - default: - w->radius = 0; - } - - addlist(&weathers, w); - - return w; -} - -double distance(int x1, int y1, int x2, int y2) -{ - return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); -} - -/* Diese Funktion ermittelt für jede Region, welches Wetter in ihr - herrscht. Die Wettertypen sind dabei nach ihrer Reihenfolge in der - enumeration priorisiert. - - - Einladen - set_weather(); - - Eigentliche Auswertung - - Veränderungen des Wetters - set_weather(); - - Report generieren - - Abspeichern - - Diese Routine ist sehr rechenaufwendig! - */ - -void set_weather(void) -{ - weather_t i; - weather *w; - short x, y; - int d; - region *r; - - for (r = regions; r; r = r->next) { - r->weathertype = WEATHER_NONE; - } - - for (i = 0; i < MAXWEATHERS; i++) { - for (w = weathers; w; w = w->next) { - if (w->type == i) { - for (x = w->center[0] - w->radius; x <= w->center[0] + w->radius; x++) { - for (y = w->center[1] - w->radius; y <= w->center[1] + w->radius; y++) { - d = distance(w->center[0], w->center[1], x, y); - if (floor(d + 0.5) <= w->radius) { - r = findregion(x, y); - if (r) { - r->weathertype = w->type; - } - } - } - } - } - } - } -} - -void move_weather(void) -{ - weather *w, *wnext; - region *r; - - for (w = weathers; w;) { - wnext = w->next; - w->center[0] = w->center[0] + w->move[0]; - w->center[1] = w->center[1] + w->move[1]; - r = findregion(w->center[0], w->center[1]); - if (!r || rng_int() % 100 < 5) { - removelist(&weathers, w); - } - w = wnext; - } -} - -#else -#include -static const char *copyright = "(c) Eressea PBEM 2000"; - -void init_weather(void) -{ - fputs(copyright, stderr); - /* TODO: Initialization */ -} -#endif diff --git a/src/modules/weather.h b/src/modules/weather.h deleted file mode 100644 index 812f31ee7..000000000 --- a/src/modules/weather.h +++ /dev/null @@ -1,54 +0,0 @@ -/* -Copyright (c) 1998-2015, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_MOD_WEATHER_H -#define H_MOD_WEATHER_H -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef WEATHER -# error "the weather system is disabled" -#endif - - enum { - WEATHER_NONE, - WEATHER_STORM, - WEATHER_HURRICANE, - MAXWEATHERS - }; - - typedef unsigned char weather_t; - - typedef struct weather { - struct weather *next; - weather_t type; /* Typ der Wetterzone */ - int center[2]; /* Koordinaten des Zentrums */ - int radius; - int move[2]; - } weather; - - weather *weathers; - - void set_weather(void); - void move_weather(void); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/src/monsters.c b/src/monsters.c index 115759d29..d1979414d 100644 --- a/src/monsters.c +++ b/src/monsters.c @@ -9,7 +9,7 @@ * based on: * * Atlantis v1.0 13 September 1993 Copyright 1993 by Russell Wallace - * Atlantis v1.7 Copyright 1996 by Alex Schröder + * Atlantis v1.7 Copyright 1996 by Alex Schr�der * * This program may not be used, modified or distributed without * prior permission by the authors of Eressea. @@ -66,6 +66,7 @@ #include #include #include +#include #include @@ -74,7 +75,7 @@ #include #include -#define DRAGON_RANGE 20 /* max. Distanz zum nächsten Drachenziel */ +#define DRAGON_RANGE 20 /* max. Distanz zum n�chsten Drachenziel */ #define MOVE_PERCENT 25 /* chance fuer bewegung */ #define MAXILLUSION_TEXTS 3 @@ -82,7 +83,7 @@ static double attack_chance; /* rules.monsters.attack_chance, or default 0.4 */ static void give_peasants(unit *u, const item_type *itype, int reduce) { char buf[64]; - slprintf(buf, sizeof(buf), "%s 0 %d %s", LOC(u->faction->locale, keyword(K_GIVE)), reduce, LOC(u->faction->locale, itype->rtype->_name)); + snprintf(buf, sizeof(buf), "%s 0 %d %s", LOC(u->faction->locale, keyword(K_GIVE)), reduce, LOC(u->faction->locale, itype->rtype->_name)); unit_addorder(u, parse_order(buf, u->faction->locale)); } @@ -102,7 +103,7 @@ static void reduce_weight(unit * u) int horses = get_resource(u, get_resourcetype(R_HORSE)); if (horses > 0) { - horses = MIN(horses, (u->number * 2)); + if (horses > u->number * 2) horses = u->number * 2; change_resource(u, get_resourcetype(R_HORSE), -horses); } @@ -359,11 +360,11 @@ static direction_t random_neighbour(region * r, unit * u) } } - /* Zufällig eine auswählen */ + /* Zuf�llig eine ausw�hlen */ rr = rng_int() % c; - /* Durchzählen */ + /* Durchz�hlen */ c = 0; for (i = 0; i != MAXDIRECTIONS; i++) { @@ -400,11 +401,11 @@ static direction_t treeman_neighbour(region * r) if (c == 0) { return NODIRECTION; } - /* Zufällig eine auswählen */ + /* Zuf�llig eine ausw�hlen */ rr = rng_int() % c; - /* Durchzählen */ + /* Durchz�hlen */ c = -1; for (i = 0; i != MAXDIRECTIONS; i++) { @@ -495,7 +496,7 @@ static order *make_movement_order(unit * u, const region * target, int moves, { region *r = u->region; region **plan; - int bytes, position = 0; + int position = 0; char zOrder[128], *bufp = zOrder; size_t size = sizeof(zOrder) - 1; @@ -507,6 +508,7 @@ static order *make_movement_order(unit * u, const region * target, int moves, return NULL; while (position != moves && plan[position + 1]) { + int bytes; region *prev = plan[position]; region *next = plan[++position]; direction_t dir = reldirection(prev, next); @@ -516,7 +518,7 @@ static order *make_movement_order(unit * u, const region * target, int moves, --size; } bytes = - (int)strlcpy(bufp, + (int)str_strlcpy(bufp, (const char *)LOC(u->faction->locale, directions[dir]), size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); @@ -559,7 +561,7 @@ static order *monster_learn(unit * u) return NULL; } - /* Monster lernt ein zufälliges Talent aus allen, in denen es schon + /* Monster lernt ein zuf�lliges Talent aus allen, in denen es schon * Lerntage hat. */ for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { if (sv->level > 0) @@ -605,7 +607,6 @@ static void recruit_dracoids(unit * dragon, int size) faction *f = dragon->faction; region *r = dragon->region; const struct item *weapon = NULL; - order *new_order = NULL; unit *un = create_unit(r, f, size, get_race(RC_DRACOID), 0, NULL, NULL); fset(un, UFL_ISNEW | UFL_MOVED); @@ -617,15 +618,10 @@ static void recruit_dracoids(unit * dragon, int size) setstatus(un, ST_FIGHT); for (weapon = un->items; weapon; weapon = weapon->next) { const weapon_type *wtype = weapon->type->rtype->wtype; - if (wtype && (wtype->flags & WTF_MISSILE)) { + if (wtype && wtype->flags & WTF_MISSILE) { setstatus(un, ST_BEHIND); + break; } - new_order = create_order(K_STUDY, f->locale, "'%s'", - skillname(weapon->type->rtype->wtype->skill, f->locale)); - } - - if (new_order != NULL) { - addlist(&un->orders, new_order); } } @@ -653,7 +649,7 @@ static order *plan_dragon(unit * u) if (rc == rc_wyrm && !move) { unit *u2; for (u2 = r->units; u2; u2 = u2->next) { - /* wyrme sind einzelgänger */ + /* wyrme sind einzelg�nger */ if (u2 == u) { /* we do not make room for newcomers, so we don't need to look at them */ break; @@ -750,11 +746,11 @@ void plan_monsters(faction * f) attrib *ta; order *long_order = NULL; - /* Ab hier nur noch Befehle für NPC-Einheiten. */ + /* Ab hier nur noch Befehle f�r NPC-Einheiten. */ if (u->faction!=f) continue; - /* Befehle müssen jede Runde neu gegeben werden: */ + /* Befehle m�ssen jede Runde neu gegeben werden: */ free_orders(&u->orders); if (skill_enabled(SK_PERCEPTION)) { /* Monster bekommen jede Runde ein paar Tage Wahrnehmung dazu */ @@ -792,7 +788,7 @@ void plan_monsters(faction * f) /* Einheiten mit Bewegungsplan kriegen ein NACH: */ if (long_order == NULL) { - attrib *ta = a_find(u->attribs, &at_targetregion); + ta = a_find(u->attribs, &at_targetregion); if (ta) { if (u->region == (region *)ta->data.v) { a_remove(&u->attribs, ta); @@ -823,7 +819,7 @@ void plan_monsters(faction * f) } } if (long_order == NULL && unit_can_study(u)) { - /* Einheiten, die Waffenlosen Kampf lernen könnten, lernen es um + /* Einheiten, die Waffenlosen Kampf lernen k�nnten, lernen es um * zu bewachen: */ if (rc->bonus[SK_WEAPONLESS] != -99) { if (effskill(u, SK_WEAPONLESS, 0) < 1) { @@ -868,25 +864,33 @@ unit *spawn_seaserpent(region *r, faction *f) { } /** - * Drachen und Seeschlangen können entstehen + * Drachen und Seeschlangen k�nnen entstehen */ void spawn_dragons(void) { region *r; faction *monsters = get_or_create_monsters(); + int minage = config_get_int("monsters.spawn.min_age", 100); + int spawn_chance = 100 * config_get_int("monsters.spawn.chance", 100); + if (spawn_chance <= 0) { + /* monster spawning disabled */ + return; + } for (r = regions; r; r = r->next) { unit *u; - + if (r->age < minage) { + continue; + } if (fval(r->terrain, SEA_REGION)) { - if (rng_int() % 10000 < 1) { + if (rng_int() % spawn_chance < 1) { u = spawn_seaserpent(r, monsters); } } else if ((r->terrain == newterrain(T_GLACIER) || r->terrain == newterrain(T_SWAMP) || r->terrain == newterrain(T_DESERT)) - && rng_int() % 10000 < (5 + 100 * chaosfactor(r))) { + && rng_int() % spawn_chance < (5 + 100 * chaosfactor(r))) { if (chance(0.80)) { u = create_unit(r, monsters, nrand(60, 20) + 1, get_race(RC_FIREDRAGON), 0, NULL, NULL); } @@ -909,7 +913,7 @@ void spawn_dragons(void) } } -/** Untote können entstehen */ +/** Untote k�nnen entstehen */ void spawn_undead(void) { region *r; @@ -929,7 +933,7 @@ void spawn_undead(void) message *msg; unit *u; /* es ist sinnfrei, wenn irgendwo im Wald 3er-Einheiten Untote entstehen. - * Lieber sammeln lassen, bis sie mindestens 5% der Bevölkerung sind, und + * Lieber sammeln lassen, bis sie mindestens 5% der Bev�lkerung sind, und * dann erst auferstehen. */ int undead = unburied / (rng_int() % 2 + 1); const race *rc = NULL; @@ -987,7 +991,7 @@ void spawn_undead(void) else { int i = deathcount(r); if (i) { - /* Gräber verwittern, 3% der Untoten finden die ewige Ruhe */ + /* Gr�ber verwittern, 3% der Untoten finden die ewige Ruhe */ deathcounts(r, (int)(-i * 0.03)); } } @@ -1126,24 +1130,6 @@ void monster_kills_peasants(unit * u) } } -faction *get_or_create_monsters(void) -{ - faction *f = findfaction(MONSTER_ID); - if (!f) { - const race *rc = rc_get_or_create("dragon"); - const char *email = config_get("monster.email"); - f = addfaction(email ? email : NULL, NULL, rc, default_locale, 0); - renumber_faction(f, MONSTER_ID); - faction_setname(f, "Monster"); - fset(f, FFL_NPC | FFL_NOIDLEOUT); - } - return f; -} - -faction *get_monsters(void) { - return get_or_create_monsters(); -} - void make_zombie(unit * u) { u_setfaction(u, get_monsters()); diff --git a/src/monsters.h b/src/monsters.h index a5a3ccd15..f3ea2d362 100644 --- a/src/monsters.h +++ b/src/monsters.h @@ -35,13 +35,8 @@ extern "C" { void monster_kills_peasants(struct unit *u); bool monster_is_waiting(const struct unit *u); - struct faction *get_monsters(void); - struct faction *get_or_create_monsters(void); void make_zombie(struct unit * u); -#define MONSTER_ID 666 -#define is_monsters(f) ((f->flags & FFL_NPC) && f==get_monsters()) - #ifdef __cplusplus } #endif diff --git a/src/monsters.test.c b/src/monsters.test.c index 51f122b87..32efc6a4c 100644 --- a/src/monsters.test.c +++ b/src/monsters.test.c @@ -31,12 +31,12 @@ extern void plan_monsters(struct faction *f); extern int monster_attacks(unit * monster, bool rich_only); -static order *find_order(const char *expected, const unit *unit) +static order *find_order(const char *expected, const unit *u) { char cmd[32]; order *ord; - for (ord = unit->orders; ord; ord = ord->next) { - if (strcmp(expected, get_command(ord, cmd, sizeof(cmd))) == 0) { + for (ord = u->orders; ord; ord = ord->next) { + if (strcmp(expected, get_command(ord, u->faction->locale, cmd, sizeof(cmd))) == 0) { return ord; } } @@ -48,8 +48,7 @@ static void create_monsters(unit **up, unit **um) { region *r; faction *fp, *fm; - test_cleanup(); - + mt_register(mt_new_va("dragon_growl", "dragon:unit", "number:int", "target:region", "growl:string", NULL)); test_create_horse(); default_locale = test_create_locale(); fp = test_create_faction(NULL); @@ -62,7 +61,7 @@ static void create_monsters(unit **up, unit **um) { test_create_region(-1, 0, test_create_terrain("ocean", SEA_REGION | SWIM_INTO | FLY_INTO)); test_create_region(1, 0, 0); - r = test_create_region(0, 0, 0); + r = test_create_region(0, 0, NULL); *up = test_create_unit(fp, r); unit_setid(*up, 1); @@ -74,6 +73,7 @@ static void test_monsters_attack(CuTest * tc) { unit *u, *m; + test_setup(); create_monsters(&u, &m); setguard(m, true); @@ -82,7 +82,7 @@ static void test_monsters_attack(CuTest * tc) plan_monsters(m->faction); CuAssertPtrNotNull(tc, find_order("attack 1", m)); - test_cleanup(); + test_teardown(); } static void test_monsters_attack_ocean(CuTest * tc) @@ -90,6 +90,7 @@ static void test_monsters_attack_ocean(CuTest * tc) region *r; unit *u, *m; + test_setup(); create_monsters(&u, &m); r = findregion(-1, 0); /* ocean */ u = test_create_unit(u->faction, r); @@ -102,19 +103,20 @@ static void test_monsters_attack_ocean(CuTest * tc) plan_monsters(m->faction); CuAssertPtrNotNull(tc, find_order("attack 2", m)); - test_cleanup(); + test_teardown(); } static void test_monsters_waiting(CuTest * tc) { unit *u, *m; + test_setup(); create_monsters(&u, &m); setguard(m, true); fset(m, UFL_ISNEW); monster_attacks(m, false); CuAssertPtrEquals(tc, 0, find_order("attack 1", m)); - test_cleanup(); + test_teardown(); } static void test_seaserpent_piracy(CuTest * tc) @@ -124,6 +126,7 @@ static void test_seaserpent_piracy(CuTest * tc) race *rc; ship_type * stype; + test_setup(); create_monsters(&u, &m); stype = test_create_shiptype("yacht"); r = findregion(-1, 0); /* ocean */ @@ -145,13 +148,14 @@ static void test_seaserpent_piracy(CuTest * tc) stype->cargo = 50001; plan_monsters(m->faction); CuAssertPtrNotNull(tc, find_order("attack 2", m)); - test_cleanup(); + test_teardown(); } static void test_monsters_attack_not(CuTest * tc) { unit *u, *m; + test_setup(); create_monsters(&u, &m); setguard(m, true); @@ -162,7 +166,7 @@ static void test_monsters_attack_not(CuTest * tc) plan_monsters(m->faction); CuAssertPtrEquals(tc, 0, find_order("attack 1", m)); - test_cleanup(); + test_teardown(); } static void test_dragon_attacks_the_rich(CuTest * tc) @@ -170,6 +174,7 @@ static void test_dragon_attacks_the_rich(CuTest * tc) unit *u, *m; const item_type *i_silver; + test_setup(); create_monsters(&u, &m); init_resources(); @@ -187,7 +192,7 @@ static void test_dragon_attacks_the_rich(CuTest * tc) plan_monsters(m->faction); CuAssertPtrNotNull(tc, find_order("attack 1", m)); CuAssertPtrNotNull(tc, find_order("loot", m)); - test_cleanup(); + test_teardown(); } extern void random_growl(const unit *u, region *tr, int rand); @@ -198,6 +203,7 @@ static void test_dragon_moves(CuTest * tc) unit *u, *m; struct message *msg; + test_setup(); create_monsters(&u, &m); rsetmoney(findregion(1, 0), 1000); r = findregion(0, 0); /* plain */ @@ -210,7 +216,7 @@ static void test_dragon_moves(CuTest * tc) plan_monsters(m->faction); CuAssertPtrNotNull(tc, find_order("move east", m)); - mt_register(mt_new_va("dragon_growl", "dragon:unit", "number:int", "target:region", "growl:string", 0)); + mt_register(mt_new_va("dragon_growl", "dragon:unit", "number:int", "target:region", "growl:string", NULL)); random_growl(m, findregion(1, 0), 3); @@ -221,7 +227,7 @@ static void test_dragon_moves(CuTest * tc) assert_pointer_parameter(tc, msg, 2, findregion(1,0)); assert_string_parameter(tc, msg, 3, "growl3"); - test_cleanup(); + test_teardown(); } static void test_monsters_learn_exp(CuTest * tc) @@ -229,6 +235,7 @@ static void test_monsters_learn_exp(CuTest * tc) unit *u, *m; skill* sk; + test_setup(); create_monsters(&u, &m); config_set("study.produceexp", "30"); @@ -241,7 +248,7 @@ static void test_monsters_learn_exp(CuTest * tc) sk = unit_skill(m, SK_MELEE); CuAssertTrue(tc, sk && (sk->level > 0 || (sk->level == 0 && sk->weeks > 0))); - test_cleanup(); + test_teardown(); } static void test_spawn_seaserpent(CuTest *tc) { @@ -249,15 +256,15 @@ static void test_spawn_seaserpent(CuTest *tc) { unit *u; faction *f; race *rc; - test_cleanup(); + test_setup(); rc = test_create_race("seaserpent"); rc->flags |= RCF_NPC; - r = test_create_region(0, 0, 0); - f = test_create_faction(0); + r = test_create_region(0, 0, NULL); + f = test_create_faction(NULL); u = spawn_seaserpent(r, f); CuAssertPtrNotNull(tc, u); CuAssertPtrEquals(tc, 0, u->_name); - test_cleanup(); + test_teardown(); } CuSuite *get_monsters_suite(void) diff --git a/src/move.c b/src/move.c index de2906843..069c6ff7d 100644 --- a/src/move.c +++ b/src/move.c @@ -17,7 +17,9 @@ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. **/ +#ifdef _MSC_VER #include +#endif #include #include "move.h" #include "guard.h" @@ -75,9 +77,11 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include #include #include #include +#include #include @@ -261,6 +265,7 @@ static int ridingcapacity(const unit * u) { int vehicles = 0, vcap = 0; int animals = 0, acap = 0; + int horses; get_transporters(u->items, &animals, &acap, &vehicles, &vcap); @@ -268,19 +273,22 @@ static int ridingcapacity(const unit * u) ** tragen nichts (siehe walkingcapacity). Ein Wagen zählt nur, wenn er ** von zwei Pferden gezogen wird */ - animals = MIN(animals, effskill(u, SK_RIDING, 0) * u->number * 2); + horses = effskill(u, SK_RIDING, 0) * u->number * 2; + if (animals > horses) animals = horses; + if (fval(u_race(u), RCF_HORSE)) animals += u->number; /* maximal diese Pferde können zum Ziehen benutzt werden */ - vehicles = MIN(animals / HORSESNEEDED, vehicles); + horses = animals / HORSES_PER_CART; + if (horses < vehicles) vehicles = horses; return vehicles * vcap + animals * acap; } int walkingcapacity(const struct unit *u) { - int n, people, pferde_fuer_wagen; + int n, people, pferde_fuer_wagen, horses; int wagen_ohne_pferde, wagen_mit_pferden, wagen_mit_trollen; int vehicles = 0, vcap = 0; int animals = 0, acap = 0; @@ -292,7 +300,8 @@ int walkingcapacity(const struct unit *u) /* Das Gewicht, welches die Pferde tragen, plus das Gewicht, welches * die Leute tragen */ - pferde_fuer_wagen = MIN(animals, effskill(u, SK_RIDING, 0) * u->number * 4); + horses = effskill(u, SK_RIDING, 0) * u->number * 4; + pferde_fuer_wagen = (animals < horses) ? animals : horses; if (fval(u_race(u), RCF_HORSE)) { animals += u->number; people = 0; @@ -302,7 +311,8 @@ int walkingcapacity(const struct unit *u) } /* maximal diese Pferde können zum Ziehen benutzt werden */ - wagen_mit_pferden = MIN(vehicles, pferde_fuer_wagen / HORSESNEEDED); + horses = pferde_fuer_wagen / HORSES_PER_CART; + wagen_mit_pferden = (vehicles < horses) ? vehicles : horses; n = wagen_mit_pferden * vcap; @@ -312,7 +322,8 @@ int walkingcapacity(const struct unit *u) wagen_ohne_pferde = vehicles - wagen_mit_pferden; /* Genug Trolle, um die Restwagen zu ziehen? */ - wagen_mit_trollen = MIN(u->number / 4, wagen_ohne_pferde); + wagen_mit_trollen = u->number / 4; + if (wagen_mit_trollen > wagen_ohne_pferde) wagen_mit_trollen = wagen_ohne_pferde; /* Wagenkapazität hinzuzählen */ n += wagen_mit_trollen * vcap; @@ -336,7 +347,8 @@ int walkingcapacity(const struct unit *u) int belts = i_get(u->items, rbelt->itype); if (belts) { int multi = config_get_int("rules.trollbelt.multiplier", STRENGTHMULTIPLIER); - n += MIN(people, belts) * (multi - 1) * u_race(u)->capacity; + if (belts > people) belts = people; + n += belts * (multi - 1) * u_race(u)->capacity; } } @@ -367,7 +379,8 @@ static int canwalk(unit * u) effsk = effskill(u, SK_RIDING, 0); maxwagen = effsk * u->number * 2; if (u_race(u) == get_race(RC_TROLL)) { - maxwagen = MAX(maxwagen, u->number / 4); + int trolls = u->number / 4; + if (maxwagen > trolls) maxwagen = trolls; } maxpferde = effsk * u->number * 4 + u->number; @@ -509,8 +522,9 @@ static double overload(const region * r, ship * sh) getshipweight(sh, &n, &p); ovl = n / (double)sh->type->cargo; - if (mcabins) - ovl = MAX(ovl, p / (double)mcabins); + if (mcabins) { + ovl = fmax(ovl, p / (double)mcabins); + } return ovl; } } @@ -678,16 +692,10 @@ int check_ship_allowed(struct ship *sh, const region * r) if (sh->region && r_insectstalled(r)) { /* insekten dürfen nicht hier rein. haben wir welche? */ - unit *u; - - for (u = sh->region->units; u != NULL; u = u->next) { - if (u->ship != sh) { - continue; - } + unit *u = ship_owner(sh); - if (is_freezing(u)) { - return SA_NO_INSECT; - } + if (u && is_freezing(u)) { + return SA_NO_INSECT; } } @@ -757,7 +765,7 @@ double damage_overload(double overload) badness = overload - overload_worse(); if (badness >= 0) { assert(overload_worst() > overload_worse() || !"overload.worst must be > overload.worse"); - damage += MIN(badness, overload_worst() - overload_worse()) * + damage += fmin(badness, overload_worst() - overload_worse()) * (overload_max_damage() - damage) / (overload_worst() - overload_worse()); } @@ -787,29 +795,34 @@ static void msg_to_ship_inmates(ship *sh, unit **firstu, unit **lastu, message * msg_release(msg); } -region * drift_target(ship *sh) { - int d, d_offset = rng_int() % MAXDIRECTIONS; - region *rnext = NULL; +direction_t drift_target(ship *sh) { + direction_t d, dir = rng_int() % MAXDIRECTIONS; + direction_t result = NODIRECTION; for (d = 0; d != MAXDIRECTIONS; ++d) { region *rn; - direction_t dir = (direction_t)((d + d_offset) % MAXDIRECTIONS); - rn = rconnect(sh->region, dir); + direction_t dn = (direction_t)((d + dir) % MAXDIRECTIONS); + rn = rconnect(sh->region, dn); if (rn != NULL && check_ship_allowed(sh, rn) >= 0) { - rnext = rn; - if (!fval(rnext->terrain, SEA_REGION)) { + result = dn; + if (!fval(rn->terrain, SEA_REGION)) { /* prefer drifting towards non-ocean regions */ break; } } } - return rnext; + return result; } static void drifting_ships(region * r) { - bool drift = config_get_int("rules.ship.drifting", 1) != 0; - double damage_drift = config_get_flt("rules.ship.damage_drift", 0.02); + static int config; + static bool drift; + static double damage_drift; + if (config_changed(&config)) { + drift = config_get_int("rules.ship.drifting", 1) != 0; + damage_drift = config_get_flt("rules.ship.damage_drift", 0.02); + } if (fval(r->terrain, SEA_REGION)) { ship **shp = &r->ships; while (*shp) { @@ -817,7 +830,7 @@ static void drifting_ships(region * r) region *rnext = NULL; region_list *route = NULL; unit *firstu = r->units, *lastu = NULL, *captain; - direction_t dir = 0; + direction_t dir = NODIRECTION; double ovl; if (sh->type->fishing > 0) { @@ -846,13 +859,13 @@ static void drifting_ships(region * r) } ovl = overload(r, sh); - if (ovl >= overload_start()) { - rnext = NULL; - } - else { + if (ovl < overload_start()) { /* Auswahl einer Richtung: Zuerst auf Land, dann * zufällig. Falls unmögliches Resultat: vergiß es. */ - rnext = drift_target(sh); + dir = drift_target(sh); + if (dir != NODIRECTION) { + rnext = rconnect(sh->region, dir); + } } if (rnext != NULL) { @@ -877,8 +890,9 @@ static void drifting_ships(region * r) damage_ship(sh, damage_overload(ovl)); msg_to_ship_inmates(sh, &firstu, &lastu, msg_message("massive_overload", "ship", sh)); } - else + else { damage_ship(sh, damage_drift); + } if (sh->damage >= sh->size * DAMAGE_SCALE) { msg_to_ship_inmates(sh, &firstu, &lastu, msg_message("shipsink", "ship", sh)); remove_ship(&sh->region->ships, sh); @@ -951,7 +965,7 @@ static unit *bewegung_blockiert_von(unit * reisender, region * r) double prob_u = (sk - stealth) * skill_prob; guard_count += u->number; /* amulet counts at most once */ - prob_u += MIN(1, MIN(u->number, i_get(u->items, ramulet->itype))) * amulet_prob; + prob_u += fmin(1, fmin(u->number, i_get(u->items, ramulet->itype))) * amulet_prob; if (u->building && (u->building->type == castle_bt) && u == building_owner(u->building)) prob_u += castle_prob*buildingeffsize(u->building, 0); if (prob_u >= prob) { @@ -1042,15 +1056,6 @@ int movewhere(const unit * u, const char *token, region * r, region ** resultp) return E_MOVE_OK; } -static const char *shortdirections[MAXDIRECTIONS] = { - "dir_nw", - "dir_ne", - "dir_east", - "dir_se", - "dir_sw", - "dir_west" -}; - static void cycle_route(order * ord, unit * u, int gereist) { int cm = 0; @@ -1063,13 +1068,11 @@ static void cycle_route(order * ord, unit * u, int gereist) order *norder; size_t size = sizeof(tail) - 1; - if (getkeyword(ord) != K_ROUTE) - return; + assert(getkeyword(ord) == K_ROUTE); tail[0] = '\0'; + neworder[0] = '\0'; + init_order(ord, u->faction->locale); - init_order(ord); - - neworder[0] = 0; for (cm = 0;; ++cm) { const char *s; const struct locale *lang = u->faction->locale; @@ -1092,6 +1095,7 @@ static void cycle_route(order * ord, unit * u, int gereist) assert(!pause); if (!pause) { const char *loc = LOC(lang, shortdirections[d]); + assert(loc); if (bufp != tail) { bufp = STRLCPY_EX(bufp, " ", &size, "cycle_route"); } @@ -1111,15 +1115,15 @@ static void cycle_route(order * ord, unit * u, int gereist) * hier keine normale direction), muss jede PAUSE einzeln * herausgefiltert und explizit gesetzt werden */ if (neworder != obuf) { - obuf += strlcat(obuf, " ", sizeof(neworder) - (obuf - neworder)); + obuf += str_strlcat(obuf, " ", sizeof(neworder) - (obuf - neworder)); } - obuf += strlcat(obuf, LOC(lang, parameters[P_PAUSE]), sizeof(neworder) - (obuf - neworder)); + obuf += str_strlcat(obuf, LOC(lang, parameters[P_PAUSE]), sizeof(neworder) - (obuf - neworder)); } else { if (neworder != obuf) { - obuf += strlcat(obuf, " ", sizeof(neworder) - (obuf - neworder)); + obuf += str_strlcat(obuf, " ", sizeof(neworder) - (obuf - neworder)); } - obuf += strlcat(obuf, LOC(lang, shortdirections[d]), sizeof(neworder) - (obuf - neworder)); + obuf += str_strlcat(obuf, LOC(lang, shortdirections[d]), sizeof(neworder) - (obuf - neworder)); } } @@ -1144,7 +1148,7 @@ static bool transport(unit * ut, unit * u) for (ord = ut->orders; ord; ord = ord->next) { if (getkeyword(ord) == K_TRANSPORT) { unit *u2; - init_order(ord); + init_order_depr(ord); getunit(ut->region, ut->faction, &u2); if (u2 == u) { return true; @@ -1178,7 +1182,7 @@ static void init_transportation(void) && !fval(u, UFL_NOTMOVING) && !LongHunger(u)) { unit *ut = 0; - init_order(u->thisorder); + init_order_depr(u->thisorder); if (getunit(r, u->faction, &ut) != GET_UNIT) { ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "feedback_unit_not_found", "")); @@ -1207,7 +1211,7 @@ static void init_transportation(void) for (ord = u->orders; ord; ord = ord->next) { if (getkeyword(ord) == K_TRANSPORT) { - init_order(ord); + init_order_depr(ord); for (;;) { unit *ut = 0; @@ -1218,7 +1222,7 @@ static void init_transportation(void) can_move(ut) && !fval(ut, UFL_NOTMOVING) && !LongHunger(ut)) { unit *u2; - init_order(ut->thisorder); + init_order_depr(ut->thisorder); getunit(r, ut->faction, &u2); if (u2 == u) { w += weight(ut); @@ -1371,7 +1375,7 @@ static void make_route(unit * u, order * ord, region_list ** routep) current = next; s = gettoken(token, sizeof(token)); error = movewhere(u, s, current, &next); - if (error) { + if (error != E_MOVE_OK) { message *msg = movement_error(u, s, ord, error); if (msg != NULL) { add_message(&u->faction->msgs, msg); @@ -1397,47 +1401,45 @@ int movement_speed(const unit * u) const race *rc = u_race(u); double dk = rc->speed; assert(u->number); + /* dragons have a fixed speed, and no other effects work on them: */ - if (fval(rc, RCF_DRAGON)) { - return BP_DRAGON; - } - switch (old_race(u_race(u))) { - case RC_BIRTHDAYDRAGON: /* FIXME: catdragon has RCF_DRAGON, so this cannot happen */ - case RC_SONGDRAGON: + if (u_race(u) == get_race(RC_SONGDRAGON)) { mp = BP_DRAGON; - break; - default: - mp = walk_mode(u); - if (mp>=BP_RIDING) { - dk = 1.0; - } - break; } - - if (u->attribs) { - curse *c = get_curse(u->attribs, &ct_speed); - if (c != NULL) { - int men = get_cursedmen(u, c); - dk *= 1.0 + (double)men / (double)u->number; + else { + if (fval(rc, RCF_DRAGON)) { + mp = BP_DRAGON; } - } - - /* unicorn in inventory */ - if (u->number <= i_get(u->items, it_find("fairyboot"))) { - mp *= 2; - } + else { + mp = walk_mode(u); + if (mp >= BP_RIDING) { + dk = 1.0; + } + if (u->attribs) { + curse *c = get_curse(u->attribs, &ct_speed); + if (c != NULL) { + int men = get_cursedmen(u, c); + dk *= 1.0 + (double)men / (double)u->number; + } + } - /* Im Astralraum sind Tyb und Ill-Magier doppelt so schnell. - * Nicht kumulativ mit anderen Beschleunigungen! */ - if (mp * dk <= BP_WALKING * u_race(u)->speed && is_astral(u->region)) { - sc_mage *mage = get_mage(u); - if (mage && (mage->magietyp == M_TYBIED || mage->magietyp == M_ILLAUN)) { - if (has_skill(u, SK_MAGIC)) { + /* unicorn in inventory */ + if (u->number <= i_get(u->items, it_find("fairyboot"))) { mp *= 2; } + + /* Im Astralraum sind Tyb und Ill-Magier doppelt so schnell. + * Nicht kumulativ mit anderen Beschleunigungen! */ + if (mp * dk <= BP_WALKING * u_race(u)->speed && is_astral(u->region)) { + sc_mage *mage = get_mage(u); + if (mage && (mage->magietyp == M_TYBIED || mage->magietyp == M_ILLAUN)) { + if (has_skill(u, SK_MAGIC)) { + mp *= 2; + } + } + } } } - return (int)(dk * mp); } @@ -1606,7 +1608,9 @@ static const region_list *travel_route(unit * u, int walkmode; setguard(u, false); - cycle_route(ord, u, steps); + if (getkeyword(ord) == K_ROUTE) { + cycle_route(ord, u, steps); + } if (mode == TRAVEL_RUNNING) { walkmode = 0; @@ -1764,9 +1768,9 @@ static void sail(unit * u, order * ord, region_list ** routep, bool drifting) } if (!flying_ship(sh)) { - int stormchance = 0; int reason; if (storms_enabled) { + int stormchance = 0; int stormyness; gamedate date; get_gamedate(turn, &date); @@ -1936,7 +1940,9 @@ static void sail(unit * u, order * ord, region_list ** routep, bool drifting) unit *harbourmaster; /* nachdem alle Richtungen abgearbeitet wurden, und alle Einheiten * transferiert wurden, kann der aktuelle Befehl gelöscht werden. */ - cycle_route(ord, u, step); + if (getkeyword(ord) == K_ROUTE) { + cycle_route(ord, u, step); + } set_order(&u->thisorder, NULL); set_coast(sh, last_point, current_point); @@ -1974,8 +1980,8 @@ static void sail(unit * u, order * ord, region_list ** routep, bool drifting) const luxury_type *ltype = resource2luxury(itm->type->rtype); if (ltype != NULL && itm->number > 0) { int st = itm->number * effskill(harbourmaster, SK_TRADE, 0) / 50; - st = MIN(itm->number, st); + if (st > itm->number) st = itm->number; if (st > 0) { i_change(&u2->items, itm->type, -st); i_change(&harbourmaster->items, itm->type, st); @@ -2026,7 +2032,7 @@ static const region_list *travel_i(unit * u, const region_list * route_begin, region *r = u->region; int mp; if (u->building && !can_leave(u)) { - cmistake(u, u->thisorder, 150, MSG_MOVE); + cmistake(u, ord, 150, MSG_MOVE); return route_begin; } switch (canwalk(u)) { @@ -2062,7 +2068,7 @@ static const region_list *travel_i(unit * u, const region_list * route_begin, if (getkeyword(ord) != K_TRANSPORT) continue; - init_order(ord); + init_order_depr(ord); if (getunit(r, u->faction, &ut) == GET_UNIT) { if (getkeyword(ut->thisorder) == K_DRIVE) { if (ut->building && !can_leave(ut)) { @@ -2077,7 +2083,7 @@ static const region_list *travel_i(unit * u, const region_list * route_begin, if (!fval(ut, UFL_NOTMOVING) && !LongHunger(ut)) { unit *u2; - init_order(ut->thisorder); + init_order_depr(ut->thisorder); getunit(u->region, ut->faction, &u2); if (u2 == u) { const region_list *route_to = @@ -2115,7 +2121,7 @@ static const region_list *travel_i(unit * u, const region_list * route_begin, /** traveling without ships * walking, flying or riding units use this function */ -static void travel(unit * u, region_list ** routep) +static void travel(unit * u, order *ord, region_list ** routep) { region *r = u->region; region_list *route_begin; @@ -2129,7 +2135,7 @@ static void travel(unit * u, region_list ** routep) ship *sh = u->ship; if (!can_leave(u)) { - cmistake(u, u->thisorder, 150, MSG_MOVE); + cmistake(u, ord, 150, MSG_MOVE); return; } @@ -2142,28 +2148,28 @@ static void travel(unit * u, region_list ** routep) if (sh) { unit *guard = is_guarded(r, u); if (guard) { - ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "region_guarded", "guard", guard)); return; } } if (u->ship && u_race(u)->flags & RCF_SWIM) { - cmistake(u, u->thisorder, 143, MSG_MOVE); + cmistake(u, ord, 143, MSG_MOVE); return; } } else if (u->ship && fval(u->ship, SF_MOVED)) { /* die Einheit ist auf einem Schiff, das sich bereits bewegt hat */ - cmistake(u, u->thisorder, 13, MSG_MOVE); + cmistake(u, ord, 13, MSG_MOVE); return; } - make_route(u, u->thisorder, routep); + make_route(u, ord, routep); route_begin = *routep; if (route_begin) { /* und ab die post: */ - travel_i(u, route_begin, NULL, u->thisorder, TRAVEL_NORMAL, &followers); + travel_i(u, route_begin, NULL, ord, TRAVEL_NORMAL, &followers); /* followers */ while (followers != NULL) { @@ -2204,7 +2210,7 @@ void move_cmd(unit * u, order * ord) sail(u, ord, &route, drifting); } else { - travel(u, &route); + travel(u, ord, &route); } fset(u, UFL_LONGACTION | UFL_NOTMOVING); @@ -2295,7 +2301,7 @@ int follow_ship(unit * u, order * ord) moves = 1; - speed = (int)getuint(); + speed = getuint(); if (speed == 0) { speed = shipspeed(u->ship, u); } @@ -2323,22 +2329,6 @@ int follow_ship(unit * u, order * ord) return 1; /* true -> Einheitenliste von vorne durchgehen */ } -void destroy_damaged_ships(void) -{ - region *r; - ship *sh, *shn; - - for (r = regions; r; r = r->next) { - for (sh = r->ships; sh;) { - shn = sh->next; - if (sh->damage >= sh->size * DAMAGE_SCALE) { - remove_ship(&sh->region->ships, sh); - } - sh = shn; - } - } -} - /* Bewegung, Verfolgung, Piraterie */ /** ships that folow other ships @@ -2363,7 +2353,7 @@ static void move_hunters(void) if (getkeyword(ord) == K_FOLLOW) { param_t p; - init_order(ord); + init_order_depr(ord); p = getparam(u->faction->locale); if (p != P_SHIP) { if (p != P_UNIT) { @@ -2485,13 +2475,13 @@ void movement(void) else { if (ships) { if (u->ship && ship_owner(u->ship) == u) { - init_order(u->thisorder); + init_order_depr(u->thisorder); move_cmd(u, u->thisorder); } } else { if (!u->ship || ship_owner(u->ship) != u) { - init_order(u->thisorder); + init_order_depr(u->thisorder); move_cmd(u, u->thisorder); } } @@ -2548,7 +2538,7 @@ void follow_unit(unit * u) if (getkeyword(ord) == K_FOLLOW) { int id; param_t p; - init_order(ord); + init_order_depr(ord); p = getparam(lang); if (p == P_UNIT) { id = read_unitid(u->faction, r); diff --git a/src/move.h b/src/move.h index 4b9c75749..84a4cdb4f 100644 --- a/src/move.h +++ b/src/move.h @@ -50,7 +50,7 @@ extern "C" { #define MV_SWIM (1<<8) /* kann schwimmen */ #define MV_WALK (1<<9) /* kann über Land gehen */ -#define HORSESNEEDED 2 +#define HORSES_PER_CART 2 /* number of horses for a cart */ #define STRENGTHMULTIPLIER 50 /* multiplier for trollbelt */ /* ein mensch wiegt 10, traegt also 5, ein pferd wiegt 50, traegt also 20. ein @@ -94,7 +94,7 @@ extern "C" { #define SA_NO_COAST -2 int check_ship_allowed(struct ship *sh, const struct region * r); - struct region * drift_target(struct ship *sh); + direction_t drift_target(struct ship *sh); #ifdef __cplusplus } #endif diff --git a/src/move.test.c b/src/move.test.c index c8fdb2436..3aca0c2ab 100644 --- a/src/move.test.c +++ b/src/move.test.c @@ -27,6 +27,11 @@ #include #include +static void setup_move(void) { + mt_register(mt_new_va("travel", "unit:unit", "start:region", "end:region", "mode:int", "regions:regions", NULL)); + mt_register(mt_new_va("moveblocked", "unit:unit", "direction:int", NULL)); +} + static void test_ship_not_allowed_in_coast(CuTest * tc) { region *r1, *r2; @@ -34,7 +39,7 @@ static void test_ship_not_allowed_in_coast(CuTest * tc) terrain_type *ttype, *otype; ship_type *stype; - test_cleanup(); + test_setup(); ttype = test_create_terrain("glacier", LAND_REGION | ARCTIC_REGION | WALK_INTO); otype = test_create_terrain("ocean", SEA_REGION); stype = test_create_shiptype("derp"); @@ -49,7 +54,7 @@ static void test_ship_not_allowed_in_coast(CuTest * tc) CuAssertIntEquals(tc, SA_NO_COAST, check_ship_allowed(sh, r1)); stype->coasts[0] = ttype; CuAssertIntEquals(tc, SA_COAST, check_ship_allowed(sh, r1)); - test_cleanup(); + test_teardown(); } typedef struct move_fixture { @@ -67,18 +72,16 @@ static void setup_harbor(move_fixture *mf) { building * b; unit *u; - test_cleanup(); - ttype = test_create_terrain("glacier", LAND_REGION | ARCTIC_REGION | WALK_INTO); btype = test_create_buildingtype("harbour"); - sh = test_create_ship(0, 0); + sh = test_create_ship(0, NULL); r = test_create_region(0, 0, ttype); b = test_create_building(r, btype); b->flags |= BLD_MAINTAINED; - u = test_create_unit(test_create_faction(0), r); + u = test_create_unit(test_create_faction(NULL), r); u->ship = sh; ship_set_owner(u); @@ -92,44 +95,49 @@ static void test_ship_allowed_without_harbormaster(CuTest * tc) { move_fixture mf; + test_setup(); setup_harbor(&mf); CuAssertIntEquals(tc, SA_HARBOUR, check_ship_allowed(mf.sh, mf.r)); + test_teardown(); } static void test_ship_blocked_by_harbormaster(CuTest * tc) { unit *u; move_fixture mf; + test_setup(); setup_harbor(&mf); - u = test_create_unit(test_create_faction(0), mf.r); + u = test_create_unit(test_create_faction(NULL), mf.r); u->building = mf.b; building_set_owner(u); CuAssertIntEquals_Msg(tc, "harbor master must contact ship", SA_NO_COAST, check_ship_allowed(mf.sh, mf.r)); - test_cleanup(); + test_teardown(); } static void test_ship_has_harbormaster_contact(CuTest * tc) { unit *u; move_fixture mf; + test_setup(); setup_harbor(&mf); - u = test_create_unit(test_create_faction(0), mf.r); + u = test_create_unit(test_create_faction(NULL), mf.r); u->building = mf.b; building_set_owner(u); usetcontact(mf.b->_owner, mf.sh->_owner); CuAssertIntEquals(tc, SA_HARBOUR, check_ship_allowed(mf.sh, mf.r)); - test_cleanup(); + test_teardown(); } static void test_ship_has_harbormaster_same_faction(CuTest * tc) { unit *u; move_fixture mf; + test_setup(); setup_harbor(&mf); u = test_create_unit(mf.u->faction, mf.r); @@ -137,7 +145,7 @@ static void test_ship_has_harbormaster_same_faction(CuTest * tc) { building_set_owner(u); CuAssertIntEquals(tc, SA_HARBOUR, check_ship_allowed(mf.sh, mf.r)); - test_cleanup(); + test_teardown(); } static void test_ship_has_harbormaster_ally(CuTest * tc) { @@ -145,16 +153,17 @@ static void test_ship_has_harbormaster_ally(CuTest * tc) { move_fixture mf; ally *al; + test_setup(); setup_harbor(&mf); - u = test_create_unit(test_create_faction(0), mf.r); + u = test_create_unit(test_create_faction(NULL), mf.r); u->building = mf.b; building_set_owner(u); al = ally_add(&u->faction->allies, mf.u->faction); al->status = HELP_GUARD; CuAssertIntEquals(tc, SA_HARBOUR, check_ship_allowed(mf.sh, mf.r)); - test_cleanup(); + test_teardown(); } static void test_walkingcapacity(CuTest *tc) { @@ -196,7 +205,7 @@ static void test_walkingcapacity(CuTest *tc) { config_set("rules.trollbelt.multiplier", "5"); CuAssertIntEquals(tc, cap + 4 * u->_race->capacity, walkingcapacity(u)); - test_cleanup(); + test_teardown(); } static void test_ship_trails(CuTest *tc) { @@ -205,13 +214,13 @@ static void test_ship_trails(CuTest *tc) { terrain_type *otype; region_list *route = 0; - test_cleanup(); + test_setup(); otype = test_create_terrain("ocean", SEA_REGION); r1 = test_create_region(0, 0, otype); r2 = test_create_region(1, 0, otype); r3 = test_create_region(2, 0, otype); - sh = test_create_ship(r1, 0); - move_ship(sh, r1, r3, 0); + sh = test_create_ship(r1, NULL); + move_ship(sh, r1, r3, NULL); CuAssertPtrEquals(tc, r3, sh->region); CuAssertPtrEquals(tc, sh, r3->ships); CuAssertPtrEquals(tc, 0, r1->ships); @@ -227,7 +236,7 @@ static void test_ship_trails(CuTest *tc) { CuAssertPtrNotNull(tc, a_find(r2->attribs, &at_shiptrail)); CuAssertPtrNotNull(tc, a_find(r3->attribs, &at_shiptrail)); free_regionlist(route); - test_cleanup(); + test_teardown(); } static void test_age_trails(CuTest *tc) { @@ -235,10 +244,10 @@ static void test_age_trails(CuTest *tc) { region *r1, *r2; ship *sh; - test_cleanup(); - r1 = test_create_region(0, 0, 0); - r2 = test_create_region(1, 0, 0); - sh = test_create_ship(r1, 0); + test_setup(); + r1 = test_create_region(0, 0, NULL); + r2 = test_create_region(1, 0, NULL); + sh = test_create_ship(r1, NULL); add_regionlist(&route, r1); add_regionlist(&route, r2); move_ship(sh, r1, r2, route); @@ -249,7 +258,7 @@ static void test_age_trails(CuTest *tc) { a_age(&r1->attribs, r1); CuAssertPtrEquals(tc, 0, r1->attribs); free_regionlist(route); - test_cleanup(); + test_teardown(); } struct drift_fixture { @@ -263,7 +272,6 @@ struct drift_fixture { }; void setup_drift (struct drift_fixture *fix) { - test_setup(); test_create_locale(); config_set("rules.ship.storms", "0"); @@ -271,18 +279,21 @@ void setup_drift (struct drift_fixture *fix) { fix->st_boat->cabins = 20000; test_create_ocean(0, 0); - fix->u = test_create_unit(fix->f = test_create_faction(0), fix->r = test_create_ocean(-1, 0)); + fix->u = test_create_unit(fix->f = test_create_faction(NULL), fix->r = test_create_ocean(-1, 0)); assert(fix->r && fix->u && fix->f); set_level(fix->u, SK_SAILING, fix->st_boat->sumskill); u_set_ship(fix->u, fix->sh = test_create_ship(fix->u->region, fix->st_boat)); assert(fix->sh); + + mt_register(mt_new_va("ship_drift", "ship:ship", "dir:int", NULL)); + mt_register(mt_new_va("shipsink", "ship:ship", NULL)); + mt_register(mt_new_va("massive_overload", "ship:ship", NULL)); } static void test_ship_no_overload(CuTest *tc) { struct drift_fixture fix; - test_cleanup(); - + test_setup(); setup_drift(&fix); fix.u->number = 2; @@ -290,14 +301,13 @@ static void test_ship_no_overload(CuTest *tc) { CuAssertPtrEquals(tc, fix.u->region, findregion(-1,0)); CuAssertIntEquals(tc, 0, fix.sh->damage); - test_cleanup(); + test_teardown(); } static void test_ship_empty(CuTest *tc) { struct drift_fixture fix; - test_cleanup(); - + test_setup(); setup_drift(&fix); fix.u->ship = NULL; ship_update_owner(fix.sh); @@ -307,14 +317,30 @@ static void test_ship_empty(CuTest *tc) { CuAssertIntEquals(tc, 2, ship_damage_percent(fix.sh)); CuAssertPtrEquals(tc, 0, test_find_messagetype(fix.f->msgs, "ship_drift")); - test_cleanup(); + test_teardown(); } -static void test_ship_normal_overload(CuTest *tc) { +static void test_no_drift_damage(CuTest *tc) { struct drift_fixture fix; - test_cleanup(); + test_setup(); + setup_drift(&fix); + fix.u->ship = NULL; + ship_update_owner(fix.sh); + + config_set("rules.ship.damage_drift", "0.0"); + movement(); + CuAssertPtrEquals(tc, fix.sh->region, findregion(0, 0)); + CuAssertIntEquals(tc, 0, ship_damage_percent(fix.sh)); + CuAssertPtrEquals(tc, 0, test_find_messagetype(fix.f->msgs, "ship_drift")); + + test_teardown(); +} + +static void test_ship_normal_overload(CuTest *tc) { + struct drift_fixture fix; + test_setup(); setup_drift(&fix); fix.u->number = 21; @@ -323,14 +349,13 @@ static void test_ship_normal_overload(CuTest *tc) { CuAssertIntEquals(tc, 2, ship_damage_percent(fix.sh)); CuAssertPtrNotNull(tc, test_find_messagetype(fix.f->msgs, "ship_drift")); - test_cleanup(); + test_teardown(); } static void test_ship_big_overload(CuTest *tc) { struct drift_fixture fix; - test_cleanup(); - + test_setup(); setup_drift(&fix); fix.u->number = 22; @@ -339,14 +364,13 @@ static void test_ship_big_overload(CuTest *tc) { CuAssertIntEquals(tc, 5, ship_damage_percent(fix.sh)); CuAssertPtrNotNull(tc, test_find_messagetype(fix.f->msgs, "massive_overload")); - test_cleanup(); + test_teardown(); } static void test_ship_no_real_overload(CuTest *tc) { struct drift_fixture fix; - test_cleanup(); - + test_setup(); setup_drift(&fix); fix.u->number = 21; @@ -356,14 +380,13 @@ static void test_ship_no_real_overload(CuTest *tc) { CuAssertIntEquals(tc, 82, ship_damage_percent(fix.sh)); CuAssertPtrEquals(tc, 0, test_find_messagetype(fix.f->msgs, "massive_overload")); - test_cleanup(); + test_teardown(); } static void test_ship_ridiculous_overload(CuTest *tc) { struct drift_fixture fix; - test_cleanup(); - + test_setup(); setup_drift(&fix); fix.u->number = 500; @@ -371,14 +394,13 @@ static void test_ship_ridiculous_overload(CuTest *tc) { CuAssertIntEquals(tc, 37, ship_damage_percent(fix.sh)); CuAssertPtrNotNull(tc, test_find_messagetype(fix.f->msgs, "massive_overload")); - test_cleanup(); + test_teardown(); } static void test_ship_ridiculous_overload_no_captain(CuTest *tc) { struct drift_fixture fix; - test_cleanup(); - + test_setup(); setup_drift(&fix); set_level(fix.u, SK_SAILING, 0); @@ -387,13 +409,13 @@ static void test_ship_ridiculous_overload_no_captain(CuTest *tc) { CuAssertIntEquals(tc, 37, ship_damage_percent(fix.sh)); CuAssertPtrNotNull(tc, test_find_messagetype(fix.f->msgs, "massive_overload")); - test_cleanup(); + test_teardown(); } static void test_ship_ridiculous_overload_bad(CuTest *tc) { struct drift_fixture fix; - test_cleanup(); + test_setup(); setup_drift(&fix); fix.u->number = 500; @@ -403,7 +425,7 @@ static void test_ship_ridiculous_overload_bad(CuTest *tc) { CuAssertPtrNotNull(tc, test_find_messagetype(fix.f->msgs, "massive_overload")); CuAssertPtrEquals(tc, 0, fix.sh->region); CuAssertPtrNotNull(tc, test_find_messagetype(fix.f->msgs, "shipsink")); - test_cleanup(); + test_teardown(); } extern double damage_overload(double overload); @@ -437,7 +459,7 @@ static void test_follow_ship_msg(CuTest * tc) { test_setup(); init_resources(); - f = test_create_faction(0); + f = test_create_faction(NULL); r = test_create_plain(0, 0); test_create_ocean(-1, 1); /* D_NORTHWEST */ @@ -460,9 +482,9 @@ static void test_follow_ship_msg(CuTest * tc) { td->dir = D_NORTHWEST; td->age = 2; - mt_register(mt_new_va("error18", "unit:unit", "region:region", "command:order", 0)); + mt_register(mt_new_va("error18", "unit:unit", "region:region", "command:order", NULL)); - init_order(ord); + init_order_depr(ord); getstrtoken(); follow_ship(u, ord); @@ -472,25 +494,26 @@ static void test_follow_ship_msg(CuTest * tc) { CuAssertPtrNotNull(tc, p); CuAssertIntEquals(tc, K_FOLLOW, getkeyword((order *)p)); - test_cleanup(); + test_teardown(); } static void test_drifting_ships(CuTest *tc) { ship *sh; - region *r1, *r2, *r3; + region *r; terrain_type *t_ocean, *t_plain; ship_type *st_boat; + test_setup(); t_ocean = test_create_terrain("ocean", SEA_REGION); t_plain = test_create_terrain("plain", LAND_REGION); - r1 = test_create_region(0, 0, t_ocean); - r2 = test_create_region(1, 0, t_ocean); + r = test_create_region(0, 0, t_ocean); + test_create_region(1, 0, t_ocean); st_boat = test_create_shiptype("boat"); - sh = test_create_ship(r1, st_boat); - CuAssertPtrEquals(tc, r2, drift_target(sh)); - r3 = test_create_region(-1, 0, t_plain); - CuAssertPtrEquals(tc, r3, drift_target(sh)); - test_cleanup(); + sh = test_create_ship(r, st_boat); + CuAssertIntEquals(tc, D_EAST, drift_target(sh)); + test_create_region(-1, 0, t_plain); + CuAssertIntEquals(tc, D_WEST, drift_target(sh)); + test_teardown(); } static void test_ship_leave_trail(CuTest *tc) { @@ -519,7 +542,7 @@ static void test_ship_leave_trail(CuTest *tc) { CuAssertPtrEquals(tc, &at_shiptrail, (void *)r2->attribs->next->type); CuAssertPtrEquals(tc, &at_lighthouse, (void *)r2->attribs->next->next->type); free_regionlist(route); - test_cleanup(); + test_teardown(); } static void test_movement_speed(CuTest *tc) { @@ -542,13 +565,76 @@ static void test_movement_speed(CuTest *tc) { i_change(&u->items, it_horse, 1); CuAssertIntEquals(tc, BP_RIDING, movement_speed(u)); - test_cleanup(); + test_teardown(); +} + +static void test_route_cycle(CuTest *tc) { + unit *u; + region *r; + struct locale *lang; + char buffer[32]; + + test_setup(); + setup_move(); + test_create_region(1, 0, NULL); + r = test_create_region(2, 0, NULL); + lang = test_create_locale(); + CuAssertPtrNotNull(tc, LOC(lang, shortdirections[D_WEST])); + u = test_create_unit(test_create_faction(NULL), r); + u->faction->locale = lang; + CuAssertIntEquals(tc, RCF_WALK, u->_race->flags & RCF_WALK); + u->orders = create_order(K_ROUTE, u->faction->locale, "WEST EAST NW"); + CuAssertStrEquals(tc, "route WEST EAST NW", get_command(u->orders, lang, buffer, sizeof(buffer))); + init_order(u->orders, u->faction->locale); + move_cmd(u, u->orders); + CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "moveblocked")); + CuAssertIntEquals(tc, 1, u->region->x); + CuAssertStrEquals(tc, "route east nw west", get_command(u->orders, lang, buffer, sizeof(buffer))); + test_teardown(); +} + +static void test_route_pause(CuTest *tc) { + unit *u; + region *r; + struct locale *lang; + char buffer[32]; + + test_setup(); + setup_move(); + test_create_region(1, 0, NULL); + r = test_create_region(2, 0, NULL); + lang = test_create_locale(); + CuAssertPtrNotNull(tc, LOC(lang, shortdirections[D_WEST])); + u = test_create_unit(test_create_faction(NULL), r); + u->faction->locale = lang; + CuAssertIntEquals(tc, RCF_WALK, u->_race->flags & RCF_WALK); + u->orders = create_order(K_ROUTE, u->faction->locale, "PAUSE EAST NW"); + CuAssertStrEquals(tc, "route PAUSE EAST NW", get_command(u->orders, lang, buffer, sizeof(buffer))); + init_order(u->orders, u->faction->locale); + move_cmd(u, u->orders); + CuAssertIntEquals(tc, 2, u->region->x); + CuAssertStrEquals(tc, "route PAUSE EAST NW", get_command(u->orders, lang, buffer, sizeof(buffer))); + test_teardown(); +} + +static void test_movement_speed_dragon(CuTest *tc) { + unit *u; + race *rc; + + test_setup(); + rc = test_create_race("dragon"); + rc->flags |= RCF_DRAGON; + rc->speed = 1.5; + u = test_create_unit(test_create_faction(rc), test_create_region(0, 0, NULL)); + CuAssertIntEquals(tc, 6, movement_speed(u)); + test_teardown(); } CuSuite *get_move_suite(void) { CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_movement_speed); + SUITE_ADD_TEST(suite, test_movement_speed_dragon); SUITE_ADD_TEST(suite, test_walkingcapacity); SUITE_ADD_TEST(suite, test_ship_not_allowed_in_coast); SUITE_ADD_TEST(suite, test_ship_leave_trail); @@ -561,6 +647,7 @@ CuSuite *get_move_suite(void) SUITE_ADD_TEST(suite, test_age_trails); SUITE_ADD_TEST(suite, test_ship_no_overload); SUITE_ADD_TEST(suite, test_ship_empty); + SUITE_ADD_TEST(suite, test_no_drift_damage); SUITE_ADD_TEST(suite, test_ship_normal_overload); SUITE_ADD_TEST(suite, test_ship_no_real_overload); SUITE_ADD_TEST(suite, test_ship_big_overload); @@ -570,5 +657,7 @@ CuSuite *get_move_suite(void) SUITE_ADD_TEST(suite, test_ship_damage_overload); SUITE_ADD_TEST(suite, test_follow_ship_msg); SUITE_ADD_TEST(suite, test_drifting_ships); + SUITE_ADD_TEST(suite, test_route_cycle); + SUITE_ADD_TEST(suite, test_route_pause); return suite; } diff --git a/src/names.c b/src/names.c index bc740a704..d8abc077b 100644 --- a/src/names.c +++ b/src/names.c @@ -31,10 +31,11 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* util includes */ #include -#include -#include #include +#include +#include #include +#include #include /* libc includes */ @@ -101,22 +102,22 @@ static void make_name(unit *u, const char *monster, int *num_postfix, sprintf(zText, "%s_prefix_%d", monster, uv); str = locale_getstring(default_locale, zText); if (str) { - size_t sz = strlcpy(name, (const char *)str, sizeof(name)); - strlcpy(name + sz, " ", sizeof(name) - sz); + size_t sz = str_strlcpy(name, (const char *)str, sizeof(name)); + str_strlcpy(name + sz, " ", sizeof(name) - sz); } } sprintf(zText, "%s_name_%d", monster, uu); str = locale_getstring(default_locale, zText); if (str) - strlcat(name, (const char *)str, sizeof(name)); + str_strlcat(name, (const char *)str, sizeof(name)); if (un < *num_postfix) { sprintf(zText, "%s_postfix_%d", monster, un); str = locale_getstring(default_locale, zText); if (str) { - strlcat(name, " ", sizeof(name)); - strlcat(name, (const char *)str, sizeof(name)); + str_strlcat(name, " ", sizeof(name)); + str_strlcat(name, (const char *)str, sizeof(name)); } } unit_setname(u, name); @@ -248,6 +249,8 @@ static void dragon_name(unit * u) case T_GLACIER: ter = 5; break; + default: + ter = 0; } if (num_postfix <=0) { @@ -260,37 +263,34 @@ static void dragon_name(unit * u) rnd = num_postfix / 6; rnd = (rng_int() % rnd) + ter * rnd; } - sprintf(zText, "dragon_postfix_%d", rnd); + snprintf(zText, sizeof(zText), "dragon_postfix_%d", rnd); str = locale_getstring(default_locale, zText); assert(str != NULL); - if (u->number > 1) { + if (u->region->land && (u->number > 1)) { const char *no_article = strchr((const char *)str, ' '); assert(no_article); /* TODO: localization */ - sprintf(name, "Die %sn von %s", no_article + 1, rname(u->region, + snprintf(name, sizeof(name), "Die %sn von %s", no_article + 1, rname(u->region, default_locale)); } else { char n[32]; - size_t sz; - sz = strlcpy(n, silbe1[rng_int() % SIL1], sizeof(n)); - sz += strlcat(n, silbe2[rng_int() % SIL2], sizeof(n)); - sz += strlcat(n, silbe3[rng_int() % SIL3], sizeof(n)); + snprintf(n, sizeof(n), "%s%s%s", silbe1[rng_int() % SIL1], silbe2[rng_int() % SIL2], silbe3[rng_int() % SIL3]); if (rng_int() % 5 > 2) { sprintf(name, "%s, %s", n, str); /* "Name, der Titel" */ } else { - sz = strlcpy(name, (const char *)str, sizeof(name)); /* "Der Titel Name" */ + if (u->region->land && (rng_int() % 3 == 0)) { + /* TODO: localization */ + snprintf(name, sizeof(name), "%s %s von %s", n, str, rname(u->region, default_locale)); + } + else { + snprintf(name, sizeof(name), "%s %s", n, str); + } name[0] = (char)toupper(name[0]); /* TODO: UNICODE - should use towupper() */ - sz += strlcat(name, " ", sizeof(name)); - sz += strlcat(name, n, sizeof(name)); - } - if (rng_int() % 3 == 0) { - sz += strlcat(name, " von ", sizeof(name)); - sz += strlcat(name, (const char *)rname(u->region, default_locale), sizeof(name)); } } @@ -358,14 +358,14 @@ static void dracoid_name(unit * u) mid_syllabels = rng_int() % 4; - sz = strlcpy(name, drac_pre[rng_int() % DRAC_PRE], sizeof(name)); + sz = str_strlcpy(name, drac_pre[rng_int() % DRAC_PRE], sizeof(name)); while (mid_syllabels > 0) { mid_syllabels--; if (rng_int() % 10 < 4) - strlcat(name, "'", sizeof(name)); - sz += strlcat(name, drac_mid[rng_int() % DRAC_MID], sizeof(name)); + str_strlcat(name, "'", sizeof(name)); + sz += str_strlcat(name, drac_mid[rng_int() % DRAC_MID], sizeof(name)); } - sz += strlcat(name, drac_suf[rng_int() % DRAC_SUF], sizeof(name)); + sz += str_strlcat(name, drac_suf[rng_int() % DRAC_SUF], sizeof(name)); unit_setname(u, name); } diff --git a/src/names.test.c b/src/names.test.c index 7d62d4752..ec4526d71 100644 --- a/src/names.test.c +++ b/src/names.test.c @@ -15,7 +15,7 @@ static void test_names(CuTest * tc) { unit *u; race *rc; - test_cleanup(); + test_setup(); register_names(); CuAssertPtrNotNull(tc, get_function("name_undead")); CuAssertPtrNotNull(tc, get_function("name_skeleton")); @@ -27,14 +27,14 @@ static void test_names(CuTest * tc) CuAssertPtrNotNull(tc, get_function("name_dracoid")); default_locale = test_create_locale(); rc = test_create_race("undead"); - u = test_create_unit(test_create_faction(rc), test_create_region(0, 0, 0)); + u = test_create_unit(test_create_faction(rc), test_create_region(0, 0, NULL)); locale_setstring(default_locale, "undead_name_0", "Graue"); locale_setstring(default_locale, "undead_postfix_0", "Kobolde"); CuAssertPtrNotNull(tc, rc->name_unit); CuAssertTrue(tc, rc->name_unit == (race_func)get_function("name_undead")); name_unit(u); CuAssertStrEquals(tc, "Graue Kobolde", u->_name); - test_cleanup(); + test_teardown(); } static void test_monster_names(CuTest *tc) { @@ -50,7 +50,7 @@ static void test_monster_names(CuTest *tc) { rc = test_create_race("irongolem"); f = test_create_faction(rc); f->flags |= FFL_NPC; - u = test_create_unit(f, test_create_region(0, 0, 0)); + u = test_create_unit(f, test_create_region(0, 0, NULL)); unit_setname(u, "Hodor"); CuAssertPtrNotNull(tc, u->_name); name_unit(u); @@ -58,7 +58,7 @@ static void test_monster_names(CuTest *tc) { CuAssertStrEquals(tc, "Eisengolem", unit_getname(u)); u->number = 2; CuAssertStrEquals(tc, "Eisengolems", unit_getname(u)); - test_cleanup(); + test_teardown(); } CuSuite *get_names_suite(void) diff --git a/src/orderfile.c b/src/orderfile.c index 0db6a0cba..a82b599a0 100644 --- a/src/orderfile.c +++ b/src/orderfile.c @@ -101,7 +101,7 @@ static unit *unitorders(input *in, faction *f) } } } - /* Nun wird der Befehl erzeut und eingehängt */ + /* Nun wird der Befehl erzeut und eingeh�ngt */ *ordp = parse_order(s, u->faction->locale); if (*ordp) { ordp = &(*ordp)->next; @@ -136,7 +136,7 @@ static faction *factionorders(void) return 0; } /* Die Partei hat sich zumindest gemeldet, so dass sie noch - * nicht als untätig gilt */ + * nicht als unt�tig gilt */ f->lastorders = turn; } @@ -151,6 +151,7 @@ int read_orders(input *in) const char *b; int nfactions = 0; struct faction *f = NULL; + const struct locale *lang = default_locale; /* TODO: recognize UTF8 BOM */ b = in->getbuf(in->data); @@ -160,7 +161,6 @@ int read_orders(input *in) while (b) { char token[128]; - const struct locale *lang = f ? f->locale : default_locale; param_t p; const char *s; init_tokens_str(b); @@ -171,6 +171,7 @@ int read_orders(input *in) case P_FACTION: f = factionorders(); if (f) { + lang = f->locale; ++nfactions; } @@ -200,12 +201,13 @@ int read_orders(input *in) /* Falls in unitorders() abgebrochen wird, steht dort entweder eine neue * Partei, eine neue Einheit oder das File-Ende. Das switch() wird erneut * durchlaufen, und die entsprechende Funktion aufgerufen. Man darf buf - * auf alle Fälle nicht überschreiben! Bei allen anderen Einträgen hier - * muss buf erneut gefüllt werden, da die betreffende Information in nur - * einer Zeile steht, und nun die nächste gelesen werden muss. */ + * auf alle F�lle nicht �berschreiben! Bei allen anderen Eintr�gen hier + * muss buf erneut gef�llt werden, da die betreffende Information in nur + * einer Zeile steht, und nun die n�chste gelesen werden muss. */ case P_NEXT: f = NULL; + lang = default_locale; b = in->getbuf(in->data); break; diff --git a/src/orderfile.test.c b/src/orderfile.test.c index 10658a644..500c68fdf 100644 --- a/src/orderfile.test.c +++ b/src/orderfile.test.c @@ -4,6 +4,7 @@ #include "orderfile.h" #include +#include #include #include @@ -19,7 +20,7 @@ static void test_read_orders(CuTest *tc) { in.getbuf = getbuf_null; in.data = NULL; CuAssertIntEquals(tc, 0, read_orders(&in)); - test_cleanup(); + test_teardown(); } typedef struct order_list { @@ -52,7 +53,7 @@ static void test_faction_password_okay(CuTest *tc) { CuAssertIntEquals(tc, 0, read_orders(&in)); CuAssertIntEquals(tc, 2, olist.next); CuAssertIntEquals(tc, turn, f->lastorders); - test_cleanup(); + test_teardown(); } static void test_faction_password_bad(CuTest *tc) { @@ -62,6 +63,8 @@ static void test_faction_password_bad(CuTest *tc) { const char *orders[] = { "ERESSEA 1 password", NULL }; test_setup(); + mt_register(mt_new_va("wrongpasswd", "password:string", NULL)); + f = test_create_faction(NULL); renumber_faction(f, 1); CuAssertIntEquals(tc, 1, f->no); @@ -74,7 +77,7 @@ static void test_faction_password_bad(CuTest *tc) { CuAssertIntEquals(tc, 0, read_orders(&in)); CuAssertIntEquals(tc, 2, olist.next); CuAssertIntEquals(tc, turn - 1, f->lastorders); - test_cleanup(); + test_teardown(); } CuSuite *get_orderfile_suite(void) diff --git a/src/piracy.c b/src/piracy.c index 3025d484c..888a7e53a 100644 --- a/src/piracy.c +++ b/src/piracy.c @@ -1,5 +1,4 @@ #include -#include #include "piracy.h" #include "direction.h" @@ -68,8 +67,9 @@ static attrib *mk_piracy(const faction * pirate, const faction * target, static bool validate_pirate(unit *u, order *ord) { assert(u); assert(ord); - if (fval(u_race(u), RCF_SWIM | RCF_FLY)) + if (u_race(u)->flags & (RCF_SWIM | RCF_FLY)) { return true; + } if (!u->ship) { cmistake(u, ord, 144, MSG_MOVE); return false; @@ -86,7 +86,7 @@ int *parse_ids(const order *ord) { const char *s; int *il = NULL; - init_order(ord); + init_order_depr(ord); s = getstrtoken(); if (s != NULL && *s) { il = intlist_init(); @@ -155,8 +155,8 @@ void piracy_cmd(unit * u) /* TODO this could still result in an illegal movement order (through a wall or whatever) * which will be prevented by move_cmd below */ if (rc && - ((sh && !fval(rc->terrain, FORBIDDEN_REGION) && can_takeoff(sh, r, rc)) - || (canswim(u) && fval(rc->terrain, SWIM_INTO) && fval(rc->terrain, SEA_REGION)))) { + ((sh && !(rc->terrain->flags & FORBIDDEN_REGION) && can_takeoff(sh, r, rc)) + || (canswim(u) && ((rc->terrain->flags & (SWIM_INTO|SEA_REGION)) == (SWIM_INTO | SEA_REGION))))) { for (sh2 = rc->ships; sh2; sh2 = sh2->next) { unit *cap = ship_owner(sh2); @@ -211,7 +211,7 @@ void piracy_cmd(unit * u) ord = create_order(K_MOVE, u->faction->locale, "%s", LOC(u->faction->locale, directions[target_dir])); /* Bewegung ausführen */ - init_order(ord); + init_order_depr(ord); move_cmd(u, ord); free_order(ord); } diff --git a/src/piracy.test.c b/src/piracy.test.c index 33860e03f..22f5ccc5a 100644 --- a/src/piracy.test.c +++ b/src/piracy.test.c @@ -12,6 +12,7 @@ #include #include +#include #include #include @@ -21,7 +22,6 @@ static void setup_piracy(void) { struct locale *lang; ship_type *st_boat; - test_cleanup(); config_set("rules.ship.storms", "0"); lang = get_or_create_locale("de"); locale_setstring(lang, directions[D_EAST], "OSTEN"); @@ -29,6 +29,13 @@ static void setup_piracy(void) { test_create_terrain("ocean", SEA_REGION); st_boat = test_create_shiptype("boat"); st_boat->cargo = 1000; + + mt_register(mt_new_va("piratenovictim", "ship:ship", "unit:unit", "region:region", NULL)); + mt_register(mt_new_va("piratesawvictim", "ship:ship", "unit:unit", "region:region", "dir:int", NULL)); + mt_register(mt_new_va("shipsail", "ship:ship", "from:region", "to:region", NULL)); + mt_register(mt_new_va("shipfly", "ship:ship", "from:region", "to:region", NULL)); + mt_register(mt_new_va("shipnoshore", "ship:ship", "region:region", NULL)); + mt_register(mt_new_va("travel", "unit:unit", "start:region", "end:region", "mode:int", "regions:regions", NULL)); } static void setup_pirate(unit **pirate, int p_r_flags, int p_rc_flags, const char *p_shiptype, @@ -41,7 +48,7 @@ static void setup_pirate(unit **pirate, int p_r_flags, int p_rc_flags, const cha setup_piracy(); vterrain = get_or_create_terrain("terrain1"); fset(vterrain, v_r_flags); - *victim = test_create_unit(test_create_faction(0), test_create_region(1, 0, vterrain)); + *victim = test_create_unit(test_create_faction(NULL), test_create_region(1, 0, vterrain)); assert(*victim); if (v_shiptype) { @@ -53,7 +60,7 @@ static void setup_pirate(unit **pirate, int p_r_flags, int p_rc_flags, const cha st_boat->coasts[1] = 0; } - *pirate = create_unit(test_create_region(0, 0, get_or_create_terrain("terrain2")), f = test_create_faction(0), 1, rc = rc_get_or_create("pirate"), 0, 0, 0); + *pirate = create_unit(test_create_region(0, 0, get_or_create_terrain("terrain2")), f = test_create_faction(NULL), 1, rc = rc_get_or_create("pirate"), 0, 0, 0); fset(rc, p_rc_flags); assert(f && *pirate); @@ -77,15 +84,15 @@ static void test_piracy_cmd(CuTest * tc) { terrain_type *t_ocean; ship_type *st_boat; - test_cleanup(); - + test_setup(); setup_piracy(); + t_ocean = get_or_create_terrain("ocean"); st_boat = st_get_or_create("boat"); - u2 = test_create_unit(test_create_faction(0), test_create_region(1, 0, t_ocean)); + u2 = test_create_unit(test_create_faction(NULL), test_create_region(1, 0, t_ocean)); assert(u2); u_set_ship(u2, test_create_ship(u2->region, st_boat)); - u = test_create_unit(f = test_create_faction(0), r = test_create_region(0, 0, t_ocean)); + u = test_create_unit(f = test_create_faction(NULL), r = test_create_region(0, 0, t_ocean)); assert(f && u); set_level(u, SK_SAILING, st_boat->sumskill); u_set_ship(u, test_create_ship(u->region, st_boat)); @@ -101,7 +108,7 @@ static void test_piracy_cmd(CuTest * tc) { CuAssertPtrNotNullMsg(tc, "successful PIRACY message", test_find_messagetype(f->msgs, "piratesawvictim")); CuAssertPtrNotNullMsg(tc, "successful PIRACY movement", test_find_messagetype(f->msgs, "shipsail")); - test_cleanup(); + test_teardown(); } static void test_piracy_cmd_errors(CuTest * tc) { @@ -110,9 +117,9 @@ static void test_piracy_cmd_errors(CuTest * tc) { unit *u, *u2; ship_type *st_boat; - test_cleanup(); - + test_setup(); setup_piracy(); + st_boat = st_get_or_create("boat"); r = test_create_race("pirates"); u = test_create_unit(f = test_create_faction(r), test_create_region(0, 0, get_or_create_terrain("ocean"))); @@ -149,15 +156,14 @@ static void test_piracy_cmd_errors(CuTest * tc) { CuAssertPtrNotNullMsg(tc, "must specify target for PIRACY", test_find_messagetype(f->msgs, "piratenovictim")); CuAssertPtrNotNull(tc, u->thisorder); - test_cleanup(); + test_teardown(); } static void test_piracy_cmd_walking(CuTest * tc) { unit *pirate, *victim; region *r; - test_cleanup(); - + test_setup(); setup_pirate(&pirate, 0, 0, NULL, &victim, SWIM_INTO | SEA_REGION, "boat"); /* fset(rc, RCF_SWIM); */ r = pirate->region; @@ -167,7 +173,7 @@ static void test_piracy_cmd_walking(CuTest * tc) { CuAssertTrue(tc, pirate->region == r); CuAssertPtrNotNullMsg(tc, "successful PIRACY message", test_find_messagetype(pirate->faction->msgs, "error144")); - test_cleanup(); + test_teardown(); } static void test_piracy_cmd_land_to_land(CuTest * tc) { @@ -178,22 +184,21 @@ static void test_piracy_cmd_land_to_land(CuTest * tc) { const terrain_type *t_plain; const ship_type *stype; - test_cleanup(); - + test_setup(); setup_piracy(); t_plain = get_or_create_terrain("plain"); stype = test_create_shiptype("boat"); /* create a target: */ r = test_create_region(0, 0, t_plain); - f = test_create_faction(0); + f = test_create_faction(NULL); u = test_create_unit(f, r); u->ship = test_create_ship(r, stype); target = f->no; /* create a pirate: */ r = test_create_region(1, 0, t_plain); - f = test_create_faction(0); + f = test_create_faction(NULL); u = test_create_unit(f, r); u->ship = test_create_ship(r, stype); set_level(u, SK_SAILING, u->ship->type->sumskill); @@ -203,15 +208,14 @@ static void test_piracy_cmd_land_to_land(CuTest * tc) { CuAssertPtrEquals(tc, 0, u->thisorder); CuAssertPtrEquals(tc, r, u->region); - test_cleanup(); + test_teardown(); } static void test_piracy_cmd_swimmer(CuTest * tc) { unit *pirate, *victim; region *r; - test_cleanup(); - + test_setup(); setup_pirate(&pirate, 0, RCF_SWIM, NULL, &victim, SWIM_INTO | SEA_REGION, "boat"); r = pirate->region; @@ -222,7 +226,7 @@ static void test_piracy_cmd_swimmer(CuTest * tc) { CuAssertPtrNotNullMsg(tc, "successful PIRACY message", test_find_messagetype(pirate->faction->msgs, "piratesawvictim")); CuAssertPtrNotNullMsg(tc, "successful PIRACY movement", test_find_messagetype(pirate->faction->msgs, "travel")); - test_cleanup(); + test_teardown(); } CuSuite *get_piracy_suite(void) diff --git a/src/platform.h b/src/platform.h index 9e2ecfadb..fb1ace65a 100644 --- a/src/platform.h +++ b/src/platform.h @@ -4,56 +4,22 @@ #define _LP64 0 /* fix a warning in pdcurses 3.4 */ #endif -#ifndef UNILIB_H -#define UNILIB_H - #ifdef _MSC_VER -#ifndef __STDC__ -#define __STDC__ 1 // equivalent to /Za -#endif -#define NO_STRDUP -#define NO_MKDIR -#define _CRT_SECURE_NO_WARNINGS -#define _USE_MATH_DEFINES + +/* @see https://developercommunity.visualstudio.com/content/problem/69874/warning-c4001-in-standard-library-stringh-header.html */ #if _MSC_VER >= 1900 -#pragma warning(disable: 4710 4820) +#pragma warning(disable: 4710 4820 4001) #pragma warning(disable: 4100) // unreferenced formal parameter #pragma warning(disable: 4456) // declaration hides previous #pragma warning(disable: 4457) // declaration hides function parameter #pragma warning(disable: 4459) // declaration hides global -#endif -#else /* assume gcc */ -#if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L -# define va_copy(a,b) __va_copy(a,b) +#pragma warning(disable: 4224) // formal parameter was previously defined as a type #endif -#endif - -#define _POSIX_C_SOURCE 200809L +/* @see https://insanecoding.blogspot.no/2007/11/pathmax-simply-isnt.html */ +#define PATH_MAX 260 -#ifndef MAX_PATH -# define MAX_PATH 4096 #endif -#define UNUSED_ARG(a) (void)(a) - #define MIN(a, b) (((a) < (b)) ? (a) : (b)) #define MAX(a, b) (((a) > (b)) ? (a) : (b)) - -#define TOLUA_CAST (char*) - -#ifdef NO_STRDUP -char * strdup(const char *s); -#endif - -#ifdef NO_MKDIR -int mkdir(const char *pathname, int mode); -#endif - -/* do not use M_PI, use one of these instead: */ -#define PI_F 3.1415926535897932384626433832795F -#define PI_D 3.1415926535897932384626433832795 -#define PI_L 3.1415926535897932384626433832795L - - -#endif diff --git a/src/prefix.c b/src/prefix.c index 1a22e6982..f40a08091 100644 --- a/src/prefix.c +++ b/src/prefix.c @@ -2,6 +2,7 @@ #include "prefix.h" #include +#include #include #include @@ -30,7 +31,7 @@ int add_raceprefix(const char *prefix) race_prefixes = tmp; size *= 2; } - race_prefixes[next++] = strdup(prefix); + race_prefixes[next++] = str_strdup(prefix); race_prefixes[next] = NULL; return 0; } diff --git a/src/prefix.test.c b/src/prefix.test.c index a914426fa..f131813d7 100644 --- a/src/prefix.test.c +++ b/src/prefix.test.c @@ -1,3 +1,7 @@ +#ifdef _MSC_VER +#include +#endif + #include "prefix.h" #include @@ -18,7 +22,7 @@ static void test_add_prefix(CuTest *tc) { CuAssertPtrEquals(tc, 0, race_prefixes[2]); free_prefixes(); CuAssertPtrEquals(tc, 0, race_prefixes); - test_cleanup(); + test_teardown(); } CuSuite *get_prefix_suite(void) diff --git a/src/races/zombies.c b/src/races/zombies.c index ea26298b2..74bf53a76 100644 --- a/src/races/zombies.c +++ b/src/races/zombies.c @@ -1,6 +1,4 @@ /* - * - * * Eressea PB(E)M host Copyright (C) 1998-2015 * Christian Schlittchen (corwin@amber.kn-bremen.de) * Katja Zedel (katze@felidae.kn-bremen.de) diff --git a/src/randenc.c b/src/randenc.c index b2b282eb1..499591294 100644 --- a/src/randenc.c +++ b/src/randenc.c @@ -53,7 +53,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* util includes */ #include -#include #include #include #include @@ -62,10 +61,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include /* libc includes */ -#include #include #include #include +#include #include #include @@ -234,9 +233,9 @@ void find_manual(region * r, unit * u) break; } - slprintf(zLocation, sizeof(zLocation), "manual_location_%d", + snprintf(zLocation, sizeof(zLocation), "manual_location_%d", (int)(rng_int() % 4)); - slprintf(zBook, sizeof(zLocation), "manual_title_%s", skillnames[skill]); + snprintf(zBook, sizeof(zLocation), "manual_title_%s", skillnames[skill]); msg = msg_message("find_manual", "unit location book", u, zLocation, zBook); if (msg) { @@ -432,7 +431,7 @@ void drown(region * r) } } -static void melt_iceberg(region * r) +static void melt_iceberg(region * r, const terrain_type *t_ocean) { attrib *a; unit *u; @@ -456,11 +455,7 @@ static void melt_iceberg(region * r) } /* in Ozean wandeln */ - terraform_region(r, newterrain(T_OCEAN)); - - /* Einheiten, die nicht schwimmen k�nnen oder in Schiffen sind, - * ertrinken */ - drown(r); + terraform_region(r, t_ocean); } static void move_iceberg(region * r) @@ -589,14 +584,20 @@ static void move_iceberg(region * r) static void move_icebergs(void) { region *r; + static int terrain_cache; + static const terrain_type *t_iceberg, *t_ocean; + if (terrain_changed(&terrain_cache)) { + t_iceberg = newterrain(T_ICEBERG); + t_ocean = newterrain(T_OCEAN); + } for (r = regions; r; r = r->next) { - if (r->terrain == newterrain(T_ICEBERG) && !fval(r, RF_SELECT)) { + if (r->terrain == t_iceberg && !fval(r, RF_SELECT)) { int select = rng_int() % 10; if (select < 4) { /* 4% chance */ fset(r, RF_SELECT); - melt_iceberg(r); + melt_iceberg(r, t_ocean); } else if (select < 64) { /* 60% chance */ @@ -610,9 +611,14 @@ static void move_icebergs(void) void create_icebergs(void) { region *r; + const struct terrain_type *t_iceberg, *t_sleep; + + t_iceberg = get_terrain("iceberg"); + t_sleep = get_terrain("iceberg_sleep"); + assert(t_iceberg && t_sleep); for (r = regions; r; r = r->next) { - if (r->terrain == newterrain(T_ICEBERG_SLEEP) && chance(0.05)) { + if (r->terrain == t_sleep && chance(0.05)) { bool has_ocean_neighbour = false; direction_t dir; region *rc; @@ -629,7 +635,7 @@ void create_icebergs(void) if (!has_ocean_neighbour) continue; - rsetterrain(r, T_ICEBERG); + r->terrain = t_iceberg; fset(r, RF_SELECT); move_iceberg(r); @@ -669,10 +675,11 @@ static void godcurse(void) double dmg = config_get_flt("rules.ship.damage.godcurse", 0.1); damage_ship(sh, dmg); if (sh->damage >= sh->size * DAMAGE_SCALE) { - unit *u = ship_owner(sh); - if (u) - ADDMSG(&u->faction->msgs, - msg_message("godcurse_destroy_ship", "ship", sh)); + unit *uo = ship_owner(sh); + if (uo) { + ADDMSG(&uo->faction->msgs, + msg_message("godcurse_destroy_ship", "ship", sh)); + } remove_ship(&sh->region->ships, sh); } sh = shn; @@ -750,12 +757,8 @@ static void demon_skillchanges(void) */ static void icebergs(void) { - region *r; create_icebergs(); move_icebergs(); - for (r = regions; r; r = r->next) { - drown(r); - } } #define HERBS_ROT /* herbs owned by units have a chance to rot. */ @@ -801,11 +804,18 @@ void randomevents(void) region *r; faction *monsters = get_monsters(); - icebergs(); + if (config_get_int("modules.iceberg", 0)) { + icebergs(); + } + for (r = regions; r; r = r->next) { + drown(r); + } godcurse(); orc_growth(); demon_skillchanges(); - volcano_update(); + if (volcano_module()) { + volcano_update(); + } /* Monumente zerfallen, Schiffe verfaulen */ for (r = regions; r; r = r->next) { diff --git a/src/renumber.c b/src/renumber.c index 5f1fc3537..1319eaa5f 100644 --- a/src/renumber.c +++ b/src/renumber.c @@ -80,7 +80,7 @@ int renumber_cmd(unit * u, order * ord) int i = 0; faction *f = u->faction; - init_order(ord); + init_order_depr(ord); s = gettoken(token, sizeof(token)); switch (findparam_ex(s, u->faction->locale)) { diff --git a/src/renumber.test.c b/src/renumber.test.c index c512367b8..0c2030379 100644 --- a/src/renumber.test.c +++ b/src/renumber.test.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -19,7 +20,7 @@ static void test_renumber_faction(CuTest *tc) { const struct locale *lang; test_setup_ex(tc); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); no = u->faction->no; uno = (no > 1) ? no - 1 : no + 1; lang = u->faction->locale; @@ -27,7 +28,7 @@ static void test_renumber_faction(CuTest *tc) { renumber_cmd(u, u->thisorder); renumber_factions(); CuAssertIntEquals(tc, uno, u->faction->no); - test_cleanup(); + test_teardown(); } static void test_renumber_faction_duplicate(CuTest *tc) { @@ -37,8 +38,9 @@ static void test_renumber_faction_duplicate(CuTest *tc) { const struct locale *lang; test_setup_ex(tc); - f2 = test_create_faction(0); - u = test_create_unit(f = test_create_faction(0), test_create_region(0, 0, 0)); + mt_register(mt_new_va("renumber_inuse", "id:int", NULL)); + f2 = test_create_faction(NULL); + u = test_create_unit(f = test_create_faction(NULL), test_create_region(0, 0, NULL)); no = f->no; lang = f->locale; u->thisorder = create_order(K_NUMBER, lang, "%s %s", LOC(lang, parameters[P_FACTION]), itoa36(f2->no)); @@ -46,7 +48,7 @@ static void test_renumber_faction_duplicate(CuTest *tc) { renumber_factions(); CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "renumber_inuse")); CuAssertIntEquals(tc, no, u->faction->no); - test_cleanup(); + test_teardown(); } static void test_renumber_faction_invalid(CuTest *tc) { @@ -77,7 +79,7 @@ static void test_renumber_faction_invalid(CuTest *tc) { renumber_cmd(u, u->thisorder); CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error114")); - test_cleanup(); + test_teardown(); } static void test_renumber_building(CuTest *tc) { @@ -86,15 +88,15 @@ static void test_renumber_building(CuTest *tc) { const struct locale *lang; test_setup_ex(tc); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); - u->building = test_create_building(u->region, 0); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); + u->building = test_create_building(u->region, NULL); no = u->building->no; uno = (no > 1) ? no - 1 : no + 1; lang = u->faction->locale; u->thisorder = create_order(K_NUMBER, lang, "%s %s", LOC(lang, parameters[P_BUILDING]), itoa36(uno)); renumber_cmd(u, u->thisorder); CuAssertIntEquals(tc, uno, u->building->no); - test_cleanup(); + test_teardown(); } static void test_renumber_building_duplicate(CuTest *tc) { @@ -104,17 +106,17 @@ static void test_renumber_building_duplicate(CuTest *tc) { const struct locale *lang; test_setup_ex(tc); - u = test_create_unit(f = test_create_faction(0), test_create_region(0, 0, 0)); - u->building = test_create_building(u->region, 0); + u = test_create_unit(f = test_create_faction(NULL), test_create_region(0, 0, NULL)); + u->building = test_create_building(u->region, NULL); uno = u->building->no; - u->building = test_create_building(u->region, 0); + u->building = test_create_building(u->region, NULL); no = u->building->no; lang = f->locale; u->thisorder = create_order(K_NUMBER, lang, "%s %s", LOC(lang, parameters[P_BUILDING]), itoa36(uno)); renumber_cmd(u, u->thisorder); CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error115")); CuAssertIntEquals(tc, no, u->building->no); - test_cleanup(); + test_teardown(); } static void test_renumber_ship(CuTest *tc) { @@ -123,15 +125,15 @@ static void test_renumber_ship(CuTest *tc) { const struct locale *lang; test_setup_ex(tc); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); - u->ship = test_create_ship(u->region, 0); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); + u->ship = test_create_ship(u->region, NULL); no = u->ship->no; uno = (no > 1) ? no - 1 : no + 1; lang = u->faction->locale; u->thisorder = create_order(K_NUMBER, lang, "%s %s", LOC(lang, parameters[P_SHIP]), itoa36(uno)); renumber_cmd(u, u->thisorder); CuAssertIntEquals(tc, uno, u->ship->no); - test_cleanup(); + test_teardown(); } static void test_renumber_ship_twice(CuTest *tc) { @@ -140,8 +142,8 @@ static void test_renumber_ship_twice(CuTest *tc) { const struct locale *lang; test_setup_ex(tc); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); - u->ship = test_create_ship(u->region, 0); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); + u->ship = test_create_ship(u->region, NULL); no = u->ship->no; uno = (no > 1) ? no - 1 : no + 1; lang = u->faction->locale; @@ -152,7 +154,7 @@ static void test_renumber_ship_twice(CuTest *tc) { u->thisorder = create_order(K_NUMBER, lang, "%s %s", LOC(lang, parameters[P_SHIP]), itoa36(no)); renumber_cmd(u, u->thisorder); CuAssertIntEquals(tc, no, u->ship->no); - test_cleanup(); + test_teardown(); } static void test_renumber_ship_duplicate(CuTest *tc) { @@ -162,17 +164,17 @@ static void test_renumber_ship_duplicate(CuTest *tc) { const struct locale *lang; test_setup_ex(tc); - u = test_create_unit(f = test_create_faction(0), test_create_region(0, 0, 0)); - u->ship = test_create_ship(u->region, 0); + u = test_create_unit(f = test_create_faction(NULL), test_create_region(0, 0, NULL)); + u->ship = test_create_ship(u->region, NULL); uno = u->ship->no; - u->ship = test_create_ship(u->region, 0); + u->ship = test_create_ship(u->region, NULL); no = u->ship->no; lang = f->locale; u->thisorder = create_order(K_NUMBER, lang, "%s %s", LOC(lang, parameters[P_SHIP]), itoa36(uno)); renumber_cmd(u, u->thisorder); CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error115")); CuAssertIntEquals(tc, no, u->ship->no); - test_cleanup(); + test_teardown(); } static void test_renumber_unit(CuTest *tc) { @@ -181,7 +183,7 @@ static void test_renumber_unit(CuTest *tc) { const struct locale *lang; test_setup_ex(tc); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); no = u->no; uno = (no > 1) ? no - 1 : no + 1; lang = u->faction->locale; @@ -189,7 +191,7 @@ static void test_renumber_unit(CuTest *tc) { renumber_cmd(u, u->thisorder); CuAssertIntEquals(tc, uno, u->no); CuAssertIntEquals(tc, -no, ualias(u)); - test_cleanup(); + test_teardown(); } static void test_renumber_unit_duplicate(CuTest *tc) { @@ -199,7 +201,7 @@ static void test_renumber_unit_duplicate(CuTest *tc) { const struct locale *lang; test_setup_ex(tc); - u = test_create_unit(f = test_create_faction(0), test_create_region(0, 0, 0)); + u = test_create_unit(f = test_create_faction(NULL), test_create_region(0, 0, NULL)); no = u->no; u2 = test_create_unit(f, u->region); lang = f->locale; @@ -208,7 +210,7 @@ static void test_renumber_unit_duplicate(CuTest *tc) { CuAssertIntEquals(tc, no, u->no); CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error115")); CuAssertIntEquals(tc, 0, ualias(u)); - test_cleanup(); + test_teardown(); } static void test_renumber_unit_limit(CuTest *tc) { @@ -218,7 +220,7 @@ static void test_renumber_unit_limit(CuTest *tc) { const struct locale *lang; test_setup_ex(tc); - u = test_create_unit(f = test_create_faction(0), test_create_region(0, 0, 0)); + u = test_create_unit(f = test_create_faction(NULL), test_create_region(0, 0, NULL)); no = u->no; lang = f->locale; u->thisorder = create_order(K_NUMBER, lang, "%s 10000", LOC(lang, parameters[P_UNIT])); @@ -226,7 +228,7 @@ static void test_renumber_unit_limit(CuTest *tc) { CuAssertIntEquals(tc, no, u->no); CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error114")); CuAssertIntEquals(tc, 0, ualias(u)); - test_cleanup(); + test_teardown(); } static void test_renumber_unit_invalid(CuTest *tc) { @@ -236,7 +238,7 @@ static void test_renumber_unit_invalid(CuTest *tc) { const struct locale *lang; test_setup_ex(tc); - u = test_create_unit(f = test_create_faction(0), test_create_region(0, 0, 0)); + u = test_create_unit(f = test_create_faction(NULL), test_create_region(0, 0, NULL)); no = u->no; lang = f->locale; u->thisorder = create_order(K_NUMBER, lang, "%s TEMP", LOC(lang, parameters[P_UNIT])); @@ -244,7 +246,7 @@ static void test_renumber_unit_invalid(CuTest *tc) { CuAssertIntEquals(tc, no, u->no); CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error116")); CuAssertIntEquals(tc, 0, ualias(u)); - test_cleanup(); + test_teardown(); } CuSuite *get_renumber_suite(void) diff --git a/src/report.c b/src/report.c index 4e5eef98b..6543b153b 100644 --- a/src/report.c +++ b/src/report.c @@ -16,9 +16,9 @@ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. **/ -#define ECHECK_VERSION "4.01" - +#ifdef _MSC_VER #include +#endif #include #include "report.h" @@ -42,11 +42,11 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* gamecode includes */ #include "alchemy.h" +#include "calendar.h" #include "economy.h" #include "move.h" #include "upkeep.h" #include "vortex.h" -#include "calendar.h" #include "teleport.h" /* kernel includes */ @@ -85,8 +85,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include -#include #include +#include + +#include #include #include @@ -102,9 +104,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include -#if defined(_MSC_VER) && _MSC_VER >= 1900 -# pragma warning(disable: 4774) /* TODO: remove this */ -#endif +#define ECHECK_VERSION "4.01" extern int *storms; extern int weeks_per_month; @@ -243,12 +243,12 @@ static size_t write_spell_modifier(const spell * sp, int flag, const char * str, if (sp->sptyp & flag) { size_t bytes = 0; if (cont) { - bytes = strlcpy(bufp, ", ", size); + bytes = str_strlcpy(bufp, ", ", size); } else { - bytes = strlcpy(bufp, " ", size); + bytes = str_strlcpy(bufp, " ", size); } - bytes += strlcpy(bufp + bytes, str, size - bytes); + bytes += str_strlcpy(bufp + bytes, str, size - bytes); return bytes; } return 0; @@ -264,10 +264,10 @@ void nr_spell_syntax(struct stream *out, spellbook_entry * sbe, const struct loc const char *params = sp->parameter; if (sp->sptyp & ISCOMBATSPELL) { - bytes = (int)strlcpy(bufp, LOC(lang, keyword(K_COMBATSPELL)), size); + bytes = (int)str_strlcpy(bufp, LOC(lang, keyword(K_COMBATSPELL)), size); } else { - bytes = (int)strlcpy(bufp, LOC(lang, keyword(K_CAST)), size); + bytes = (int)str_strlcpy(bufp, LOC(lang, keyword(K_CAST)), size); } if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); @@ -334,12 +334,12 @@ void nr_spell_syntax(struct stream *out, spellbook_entry * sbe, const struct loc WARN_STATIC_BUFFER(); } else if (cp == 'r') { - bytes = (int)strlcpy(bufp, " ", size); + bytes = (int)str_strlcpy(bufp, " ", size); if (*params == '+') { ++params; if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, " [ ...]", size); + bytes = (int)str_strlcpy(bufp, " [ ...]", size); } if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); @@ -372,7 +372,7 @@ void nr_spell_syntax(struct stream *out, spellbook_entry * sbe, const struct loc ++maxparam; } if (!maxparam || maxparam > 1) { - bytes = (int)strlcpy(bufp, " (", size); + bytes = (int)str_strlcpy(bufp, " (", size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); } @@ -380,7 +380,7 @@ void nr_spell_syntax(struct stream *out, spellbook_entry * sbe, const struct loc for (targetp = targets; targetp->flag; ++targetp) { if (!maxparam || sp->sptyp & targetp->flag) { if (i++ != 0) { - bytes = (int)strlcpy(bufp, " |", size); + bytes = (int)str_strlcpy(bufp, " |", size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); } @@ -404,7 +404,7 @@ void nr_spell_syntax(struct stream *out, spellbook_entry * sbe, const struct loc } } if (!maxparam || maxparam > 1) { - bytes = (int)strlcpy(bufp, " )", size); + bytes = (int)str_strlcpy(bufp, " )", size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); } @@ -458,7 +458,7 @@ void nr_spell(struct stream *out, spellbook_entry * sbe, const struct locale *la paragraph(out, LOC(lang, "nr_spell_description"), 0, 0, 0); paragraph(out, spell_info(sp, lang), 2, 0, 0); - bytes = (int)strlcpy(bufp, LOC(lang, "nr_spell_type"), size); + bytes = (int)str_strlcpy(bufp, LOC(lang, "nr_spell_type"), size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); @@ -467,16 +467,16 @@ void nr_spell(struct stream *out, spellbook_entry * sbe, const struct locale *la --size; } if (sp->sptyp & PRECOMBATSPELL) { - bytes = (int)strlcpy(bufp, LOC(lang, "sptype_precombat"), size); + bytes = (int)str_strlcpy(bufp, LOC(lang, "sptype_precombat"), size); } else if (sp->sptyp & COMBATSPELL) { - bytes = (int)strlcpy(bufp, LOC(lang, "sptype_combat"), size); + bytes = (int)str_strlcpy(bufp, LOC(lang, "sptype_combat"), size); } else if (sp->sptyp & POSTCOMBATSPELL) { - bytes = (int)strlcpy(bufp, LOC(lang, "sptype_postcombat"), size); + bytes = (int)str_strlcpy(bufp, LOC(lang, "sptype_postcombat"), size); } else { - bytes = (int)strlcpy(bufp, LOC(lang, "sptype_normal"), size); + bytes = (int)str_strlcpy(bufp, LOC(lang, "sptype_normal"), size); } if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); @@ -522,7 +522,7 @@ void nr_spell(struct stream *out, spellbook_entry * sbe, const struct locale *la size = sizeof(buf) - 1; bufp = buf; - bytes = (int)strlcpy(buf, LOC(lang, "nr_spell_modifiers"), size); + bytes = (int)str_strlcpy(buf, LOC(lang, "nr_spell_modifiers"), size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); @@ -578,7 +578,7 @@ nr_curses_i(struct stream *out, int indent, const faction *viewer, objtype_t typ effect_data *data = (effect_data *)a->data.v; if (data->value > 0) { msg = msg_message("nr_potion_effect", "potion left", - data->type->itype->rtype, data->value); + data->type->rtype, data->value); } } if (msg) { @@ -744,8 +744,13 @@ rp_messages(struct stream *out, message_list * msgs, faction * viewer, int inden newline(out); sprintf(cat_identifier, "section_%s", section->name); section_title = LOC(viewer->locale, cat_identifier); - centre(out, section_title, true); - newline(out); + if (section_title) { + centre(out, section_title, true); + newline(out); + } + else { + log_error("no title defined for section %s in locale %s", section->name, locale_name(viewer->locale)); + } k = 1; } nr_render(m->msg, viewer->locale, lbuf, sizeof(lbuf), viewer); @@ -806,13 +811,13 @@ static void prices(struct stream *out, const region * r, const faction * f) msg_release(m); if (n > 0) { - bytes = (int)strlcpy(bufp, " ", size); + bytes = (int)str_strlcpy(bufp, " ", size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_trade_intro"), size); + bytes = (int)str_strlcpy(bufp, LOC(f->locale, "nr_trade_intro"), size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, " ", size); + bytes = (int)str_strlcpy(bufp, " ", size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); @@ -826,29 +831,29 @@ static void prices(struct stream *out, const region * r, const faction * f) msg_release(m); n--; if (n == 0) { - bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_trade_end"), + bytes = (int)str_strlcpy(bufp, LOC(f->locale, "nr_trade_end"), size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); } else if (n == 1) { - bytes = (int)strlcpy(bufp, " ", size); + bytes = (int)str_strlcpy(bufp, " ", size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_trade_final"), + bytes = (int)str_strlcpy(bufp, LOC(f->locale, "nr_trade_final"), size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, " ", size); + bytes = (int)str_strlcpy(bufp, " ", size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); } else { - bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_trade_next"), + bytes = (int)str_strlcpy(bufp, LOC(f->locale, "nr_trade_next"), size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, " ", size); + bytes = (int)str_strlcpy(bufp, " ", size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); } @@ -915,7 +920,7 @@ void report_region(struct stream *out, const region * r, faction * f) if (!r2) continue; for (b = get_borders(r, r2); b;) { - struct edge *e = edges; + struct edge *edg = edges; bool transparent = b->type->transparent(b, f); const char *name = border_name(b, r, f, GF_DETAILED | GF_ARTICLE); @@ -926,18 +931,18 @@ void report_region(struct stream *out, const region * r, faction * f) b = b->next; continue; } - while (e && (e->transparent != transparent || strcmp(name, e->name)!=0)) { - e = e->next; + while (edg && (edg->transparent != transparent || strcmp(name, edg->name)!=0)) { + edg = edg->next; } - if (!e) { - e = calloc(sizeof(struct edge), 1); - e->name = strdup(name); - e->transparent = transparent; - e->next = edges; - edges = e; + if (!edg) { + edg = calloc(sizeof(struct edge), 1); + edg->name = str_strdup(name); + edg->transparent = transparent; + edg->next = edges; + edges = edg; } - e->lastd = d; - e->exist[d] = true; + edg->lastd = d; + edg->exist[d] = true; b = b->next; } } @@ -962,19 +967,19 @@ void report_region(struct stream *out, const region * r, faction * f) WARN_STATIC_BUFFER(); /* Terrain */ - bytes = (int)strlcpy(bufp, ", ", size); + bytes = (int)str_strlcpy(bufp, ", ", size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); tname = terrain_name(r); - bytes = (int)strlcpy(bufp, LOC(f->locale, tname), size); + bytes = (int)str_strlcpy(bufp, LOC(f->locale, tname), size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); /* Trees */ trees = rtrees(r, 2); saplings = rtrees(r, 1); - if (production(r)) { + if (max_production(r)) { if (trees > 0 || saplings > 0) { bytes = snprintf(bufp, size, ", %d/%d ", trees, saplings); if (wrptr(&bufp, &size, bytes) != 0) @@ -982,17 +987,17 @@ void report_region(struct stream *out, const region * r, faction * f) if (fval(r, RF_MALLORN)) { if (trees == 1) { - bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_mallorntree"), size); + bytes = (int)str_strlcpy(bufp, LOC(f->locale, "nr_mallorntree"), size); } else { - bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_mallorntree_p"), size); + bytes = (int)str_strlcpy(bufp, LOC(f->locale, "nr_mallorntree_p"), size); } } else if (trees == 1) { - bytes = (int)strlcpy(bufp, LOC(f->locale, "tree"), size); + bytes = (int)str_strlcpy(bufp, LOC(f->locale, "tree"), size); } else { - bytes = (int)strlcpy(bufp, LOC(f->locale, "tree_p"), size); + bytes = (int)str_strlcpy(bufp, LOC(f->locale, "tree_p"), size); } if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); @@ -1002,7 +1007,7 @@ void report_region(struct stream *out, const region * r, faction * f) /* iron & stone */ if (r->seen.mode >= seen_unit) { resource_report result[MAX_RAWMATERIALS]; - int n, numresults = report_resources(r, result, MAX_RAWMATERIALS, f, true); + int numresults = report_resources(r, result, MAX_RAWMATERIALS, f, true); for (n = 0; n < numresults; ++n) { if (result[n].number >= 0 && result[n].level >= 0) { @@ -1017,8 +1022,8 @@ void report_region(struct stream *out, const region * r, faction * f) /* peasants & silver */ if (rpeasants(r)) { - int n = rpeasants(r); - bytes = snprintf(bufp, size, ", %d", n); + int p = rpeasants(r); + bytes = snprintf(bufp, size, ", %d", p); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); @@ -1029,16 +1034,16 @@ void report_region(struct stream *out, const region * r, faction * f) if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); } - bytes = (int)strlcpy(bufp, " ", size); + bytes = (int)str_strlcpy(bufp, " ", size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); bytes = - (int)strlcpy(bufp, LOC(f->locale, n == 1 ? "peasant" : "peasant_p"), + (int)str_strlcpy(bufp, LOC(f->locale, p == 1 ? "peasant" : "peasant_p"), size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); if (is_mourning(r, turn + 1)) { - bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_mourning"), size); + bytes = (int)str_strlcpy(bufp, LOC(f->locale, "nr_mourning"), size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); } @@ -1048,7 +1053,7 @@ void report_region(struct stream *out, const region * r, faction * f) if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); bytes = - (int)strlcpy(bufp, LOC(f->locale, resourcename(get_resourcetype(R_SILVER), + (int)str_strlcpy(bufp, LOC(f->locale, resourcename(get_resourcetype(R_SILVER), rmoney(r) != 1)), size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); @@ -1060,26 +1065,26 @@ void report_region(struct stream *out, const region * r, faction * f) if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); bytes = - (int)strlcpy(bufp, LOC(f->locale, resourcename(get_resourcetype(R_HORSE), + (int)str_strlcpy(bufp, LOC(f->locale, resourcename(get_resourcetype(R_HORSE), (rhorses(r) > 1) ? GR_PLURAL : 0)), size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); } - bytes = (int)strlcpy(bufp, ".", size); + bytes = (int)str_strlcpy(bufp, ".", size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); if (r->land && r->land->display && r->land->display[0]) { - bytes = (int)strlcpy(bufp, " ", size); + bytes = (int)str_strlcpy(bufp, " ", size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, r->land->display, size); + bytes = (int)str_strlcpy(bufp, r->land->display, size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); n = r->land->display[strlen(r->land->display) - 1]; if (n != '!' && n != '?' && n != '.') { - bytes = (int)strlcpy(bufp, ".", size); + bytes = (int)str_strlcpy(bufp, ".", size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); } @@ -1090,7 +1095,7 @@ void report_region(struct stream *out, const region * r, faction * f) message *msg; if (owner != NULL) { - bytes = (int)strlcpy(bufp, " ", size); + bytes = (int)str_strlcpy(bufp, " ", size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); msg = msg_message("nr_region_owner", "faction", owner); @@ -1103,10 +1108,10 @@ void report_region(struct stream *out, const region * r, faction * f) a = a_find(r->attribs, &at_overrideroads); if (a) { - bytes = (int)strlcpy(bufp, " ", size); + bytes = (int)str_strlcpy(bufp, " ", size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, (char *)a->data.v, size); + bytes = (int)str_strlcpy(bufp, (char *)a->data.v, size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); } @@ -1130,20 +1135,20 @@ void report_region(struct stream *out, const region * r, faction * f) if (dh) { char regname[4096]; if (nrd == 0) { - bytes = (int)strlcpy(bufp, " ", size); + bytes = (int)str_strlcpy(bufp, " ", size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_nb_final"), size); + bytes = (int)str_strlcpy(bufp, LOC(f->locale, "nr_nb_final"), size); } else { - bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_nb_next"), size); + bytes = (int)str_strlcpy(bufp, LOC(f->locale, "nr_nb_next"), size); } if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(f->locale, directions[d]), size); + bytes = (int)str_strlcpy(bufp, LOC(f->locale, directions[d]), size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, " ", size); + bytes = (int)str_strlcpy(bufp, " ", size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); f_regionid(r2, f, regname, sizeof(regname)); @@ -1152,7 +1157,7 @@ void report_region(struct stream *out, const region * r, faction * f) WARN_STATIC_BUFFER(); } else { - bytes = (int)strlcpy(bufp, " ", size); + bytes = (int)str_strlcpy(bufp, " ", size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); MSG(("nr_vicinitystart", "dir region", d, r2), bufp, size, f->locale, @@ -1165,23 +1170,23 @@ void report_region(struct stream *out, const region * r, faction * f) /* Spezielle Richtungen */ for (a = a_find(r->attribs, &at_direction); a && a->type == &at_direction; a = a->next) { - spec_direction *d = (spec_direction *)(a->data.v); - bytes = (int)strlcpy(bufp, " ", size); + spec_direction *spd = (spec_direction *)(a->data.v); + bytes = (int)str_strlcpy(bufp, " ", size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(f->locale, d->desc), size); + bytes = (int)str_strlcpy(bufp, LOC(f->locale, spd->desc), size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, " (\"", size); + bytes = (int)str_strlcpy(bufp, " (\"", size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(f->locale, d->keyword), size); + bytes = (int)str_strlcpy(bufp, LOC(f->locale, spd->keyword), size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, "\")", size); + bytes = (int)str_strlcpy(bufp, "\")", size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, ".", size); + bytes = (int)str_strlcpy(bufp, ".", size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); dh = 1; @@ -1201,7 +1206,7 @@ void report_region(struct stream *out, const region * r, faction * f) size = sizeof(buf) - 1; /* this localization might not work for every language but is fine for de and en */ - bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_schemes_prefix"), size); + bytes = (int)str_strlcpy(bufp, LOC(f->locale, "nr_schemes_prefix"), size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); rl2 = rl; @@ -1211,12 +1216,12 @@ void report_region(struct stream *out, const region * r, faction * f) WARN_STATIC_BUFFER(); rl2 = rl2->next; if (rl2) { - bytes = (int)strlcpy(bufp, ", ", size); + bytes = (int)str_strlcpy(bufp, ", ", size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); } } - bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_schemes_postfix"), size); + bytes = (int)str_strlcpy(bufp, LOC(f->locale, "nr_schemes_postfix"), size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); free_regionlist(rl); @@ -1244,14 +1249,14 @@ void report_region(struct stream *out, const region * r, faction * f) continue; /* this localization might not work for every language but is fine for de and en */ if (first) - bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_borderlist_prefix"), size); + bytes = (int)str_strlcpy(bufp, LOC(f->locale, "nr_borderlist_prefix"), size); else if (e->lastd == d) - bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_borderlist_lastfix"), size); + bytes = (int)str_strlcpy(bufp, LOC(f->locale, "nr_borderlist_lastfix"), size); else - bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_borderlist_infix"), size); + bytes = (int)str_strlcpy(bufp, LOC(f->locale, "nr_borderlist_infix"), size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(f->locale, directions[d]), size); + bytes = (int)str_strlcpy(bufp, LOC(f->locale, directions[d]), size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); first = false; @@ -1311,7 +1316,7 @@ static void statistics(struct stream *out, const region * r, const faction * f) paragraph(out, buf, 2, 2, 0); msg_release(m); } - if (production(r) && (!fval(r->terrain, SEA_REGION) + if (max_production(r) && (!fval(r->terrain, SEA_REGION) || f->race == get_race(RC_AQUARIAN))) { if (markets_module()) { /* hack */ m = @@ -1389,7 +1394,8 @@ static int report_template(const char *filename, report_context * ctx, const char *bom) { const resource_type *rsilver = get_resourcetype(R_SILVER); - faction *f = ctx->f; + const faction *f = ctx->f; + const struct locale *lang = f->locale; region *r; FILE *F = fopen(filename, "w"); stream strm = { 0 }, *out = &strm; @@ -1408,11 +1414,11 @@ report_template(const char *filename, report_context * ctx, const char *bom) } newline(out); - rps_nowrap(out, LOC(f->locale, "nr_template")); + rps_nowrap(out, LOC(lang, "nr_template")); newline(out); newline(out); - sprintf(buf, "%s %s \"password\"", LOC(f->locale, parameters[P_FACTION]), itoa36(f->no)); + sprintf(buf, "%s %s \"password\"", LOC(lang, parameters[P_FACTION]), itoa36(f->no)); rps_nowrap(out, buf); newline(out); newline(out); @@ -1439,12 +1445,12 @@ report_template(const char *filename, report_context * ctx, const char *bom) adjust_coordinates(f, &nx, &ny, pl); newline(out); if (pl && pl->id != 0) { - sprintf(buf, "%s %d,%d,%d ; %s", LOC(f->locale, - parameters[P_REGION]), nx, ny, pl->id, rname(r, f->locale)); + sprintf(buf, "%s %d,%d,%d ; %s", LOC(lang, + parameters[P_REGION]), nx, ny, pl->id, rname(r, lang)); } else { - sprintf(buf, "%s %d,%d ; %s", LOC(f->locale, parameters[P_REGION]), - nx, ny, rname(r, f->locale)); + sprintf(buf, "%s %d,%d ; %s", LOC(lang, parameters[P_REGION]), + nx, ny, rname(r, lang)); } rps_nowrap(out, buf); newline(out); @@ -1467,10 +1473,10 @@ report_template(const char *filename, report_context * ctx, const char *bom) if (!curse_active(get_curse(b->attribs, &ct_nocostbuilding))) { int cost = buildingmaintenance(b, rsilver); if (cost > 0) { - bytes = (int)strlcpy(bufp, ",U", size); + bytes = (int)str_strlcpy(bufp, ",U", size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, itoa10(cost), size); + bytes = (int)str_strlcpy(bufp, itoa10(cost), size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); } @@ -1478,23 +1484,23 @@ report_template(const char *filename, report_context * ctx, const char *bom) } else if (u->ship) { if (ship_owner(u->ship) == u) { - bytes = (int)strlcpy(bufp, ",S", size); + bytes = (int)str_strlcpy(bufp, ",S", size); } else { - bytes = (int)strlcpy(bufp, ",s", size); + bytes = (int)str_strlcpy(bufp, ",s", size); } if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, itoa36(u->ship->no), size); + bytes = (int)str_strlcpy(bufp, itoa36(u->ship->no), size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); } if (lifestyle(u) == 0) { - bytes = (int)strlcpy(bufp, ",I", size); + bytes = (int)str_strlcpy(bufp, ",I", size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); } - bytes = (int)strlcpy(bufp, "]", size); + bytes = (int)str_strlcpy(bufp, "]", size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); @@ -1505,7 +1511,7 @@ report_template(const char *filename, report_context * ctx, const char *bom) for (ord = u->old_orders; ord; ord = ord->next) { /* this new order will replace the old defaults */ strcpy(buf, " "); - write_order(ord, buf + 2, sizeof(buf) - 2); + write_order(ord, lang, buf + 2, sizeof(buf) - 2); rps_nowrap(out, buf); newline(out); } @@ -1515,7 +1521,7 @@ report_template(const char *filename, report_context * ctx, const char *bom) continue; /* unit has defaults */ if (is_persistent(ord)) { strcpy(buf, " "); - write_order(ord, buf + 2, sizeof(buf) - 2); + write_order(ord, lang, buf + 2, sizeof(buf) - 2); rps_nowrap(out, buf); newline(out); } @@ -1527,7 +1533,7 @@ report_template(const char *filename, report_context * ctx, const char *bom) } } newline(out); - strlcpy(buf, LOC(f->locale, parameters[P_NEXT]), sizeof(buf)); + str_strlcpy(buf, LOC(lang, parameters[P_NEXT]), sizeof(buf)); rps_nowrap(out, buf); newline(out); fstream_done(&strm); @@ -1558,24 +1564,24 @@ show_allies(const faction * f, const ally * allies, char *buf, size_t size) i++; if (dh) { if (i == allierte) { - bytes = (int)strlcpy(bufp, LOC(f->locale, "list_and"), size); + bytes = (int)str_strlcpy(bufp, LOC(f->locale, "list_and"), size); } else { - bytes = (int)strlcpy(bufp, ", ", size); + bytes = (int)str_strlcpy(bufp, ", ", size); } if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); } dh = 1; hh = 0; - bytes = (int)strlcpy(bufp, factionname(sf->faction), size); + bytes = (int)str_strlcpy(bufp, factionname(sf->faction), size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, " (", size); + bytes = (int)str_strlcpy(bufp, " (", size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); if ((mode & HELP_ALL) == HELP_ALL) { - bytes = (int)strlcpy(bufp, LOC(f->locale, parameters[P_ANY]), size); + bytes = (int)str_strlcpy(bufp, LOC(f->locale, parameters[P_ANY]), size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); } @@ -1606,22 +1612,22 @@ show_allies(const faction * f, const ally * allies, char *buf, size_t size) } if (p != MAXPARAMS) { if (hh) { - bytes = (int)strlcpy(bufp, ", ", size); + bytes = (int)str_strlcpy(bufp, ", ", size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); } - bytes = (int)strlcpy(bufp, LOC(f->locale, parameters[p]), size); + bytes = (int)str_strlcpy(bufp, LOC(f->locale, parameters[p]), size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); hh = 1; } } } - bytes = (int)strlcpy(bufp, ")", size); + bytes = (int)str_strlcpy(bufp, ")", size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); } - bytes = (int)strlcpy(bufp, ".", size); + bytes = (int)str_strlcpy(bufp, ".", size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); *bufp = 0; @@ -1696,31 +1702,31 @@ static void guards(struct stream *out, const region * r, const faction * see) size_t size = sizeof(buf) - 1; int bytes; - bytes = (int)strlcpy(bufp, LOC(see->locale, "nr_guarding_prefix"), size); + bytes = (int)str_strlcpy(bufp, LOC(see->locale, "nr_guarding_prefix"), size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); for (i = 0; i != nextguard + (tarned ? 1 : 0); ++i) { if (i != 0) { if (i == nextguard - (tarned ? 0 : 1)) { - bytes = (int)strlcpy(bufp, LOC(see->locale, "list_and"), size); + bytes = (int)str_strlcpy(bufp, LOC(see->locale, "list_and"), size); } else { - bytes = (int)strlcpy(bufp, ", ", size); + bytes = (int)str_strlcpy(bufp, ", ", size); } if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); } if (i < nextguard) { - bytes = (int)strlcpy(bufp, factionname(guardians[i]), size); + bytes = (int)str_strlcpy(bufp, factionname(guardians[i]), size); } else { - bytes = (int)strlcpy(bufp, LOC(see->locale, "nr_guarding_unknown"), size); + bytes = (int)str_strlcpy(bufp, LOC(see->locale, "nr_guarding_unknown"), size); } if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); } - bytes = (int)strlcpy(bufp, LOC(see->locale, "nr_guarding_postfix"), size); + bytes = (int)str_strlcpy(bufp, LOC(see->locale, "nr_guarding_postfix"), size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); newline(out); @@ -1753,7 +1759,7 @@ static void list_address(struct stream *out, const faction * uf, selist * seenfa char buf[8192]; char label = '-'; - sprintf(buf, "%s: %s; %s", factionname(f), f->email, + sprintf(buf, "%s: %s; %s", factionname(f), faction_getemail(f), f->banner ? f->banner : ""); if (uf == f) label = '*'; @@ -1813,26 +1819,26 @@ nr_ship(struct stream *out, const region *r, const ship * sh, const faction * f, } if (!fval(r->terrain, SEA_REGION)) { if (sh->coast != NODIRECTION) { - bytes = (int)strlcpy(bufp, ", ", size); + bytes = (int)str_strlcpy(bufp, ", ", size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(f->locale, coasts[sh->coast]), size); + bytes = (int)str_strlcpy(bufp, LOC(f->locale, coasts[sh->coast]), size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); } } ch = 0; if (sh->display && sh->display[0]) { - bytes = (int)strlcpy(bufp, "; ", size); + bytes = (int)str_strlcpy(bufp, "; ", size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, sh->display, size); + bytes = (int)str_strlcpy(bufp, sh->display, size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); ch = sh->display[strlen(sh->display) - 1]; } if (ch != '!' && ch != '?' && ch != '.') { - bytes = (int)strlcpy(bufp, ".", size); + bytes = (int)str_strlcpy(bufp, ".", size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); } @@ -1863,7 +1869,7 @@ nr_building(struct stream *out, const region *r, const building *b, const factio report_building(b, &bname, &billusion); name = LOC(lang, billusion ? billusion : bname); - bytes = (int)strlcpy(bufp, name, size); + bytes = (int)str_strlcpy(bufp, name, size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); if (billusion) { @@ -1878,7 +1884,7 @@ nr_building(struct stream *out, const region *r, const building *b, const factio } if (!building_finished(b)) { - bytes = (int)strlcpy(bufp, LOC(lang, "nr_building_inprogress"), size); + bytes = (int)str_strlcpy(bufp, LOC(lang, "nr_building_inprogress"), size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); } @@ -1893,17 +1899,17 @@ nr_building(struct stream *out, const region *r, const building *b, const factio } i = 0; if (b->display && b->display[0]) { - bytes = (int)strlcpy(bufp, "; ", size); + bytes = (int)str_strlcpy(bufp, "; ", size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, b->display, size); + bytes = (int)str_strlcpy(bufp, b->display, size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); i = b->display[strlen(b->display) - 1]; } if (i != '!' && i != '?' && i != '.') { - bytes = (int)strlcpy(bufp, ".", size); + bytes = (int)str_strlcpy(bufp, ".", size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); } @@ -2022,7 +2028,7 @@ void report_travelthru(struct stream *out, region *r, const faction *f) init_cb(&cbdata, out, buf, sizeof(buf), f); cbdata.maxtravel = maxtravel; cbdata.writep += - strlcpy(buf, LOC(f->locale, "travelthru_header"), sizeof(buf)); + str_strlcpy(buf, LOC(f->locale, "travelthru_header"), sizeof(buf)); travelthru_map(r, cb_write_travelthru, &cbdata); return; } @@ -2042,21 +2048,13 @@ report_plaintext(const char *filename, report_context * ctx, attrib *a; message *m; unsigned char op; - int maxh, bytes, ix = want(O_STATISTICS); + int maxh, bytes, ix = WANT_OPTION(O_STATISTICS); int wants_stats = (f->options & ix); FILE *F = fopen(filename, "w"); stream strm = { 0 }, *out = &strm; char buf[8192]; char *bufp; size_t size; - int thisseason; - int nextseason; - gamedate date; - - get_gamedate(turn + 1, &date); - thisseason = date.season; - get_gamedate(turn + 2, &date); - nextseason = date.season; if (F == NULL) { perror(filename); @@ -2078,7 +2076,7 @@ report_plaintext(const char *filename, report_context * ctx, newline(out); sprintf(buf, "%s, %s/%s (%s)", factionname(f), LOC(f->locale, rc_name_s(f->race, NAME_PLURAL)), - LOC(f->locale, mkname("school", magic_school[f->magiegebiet])), f->email); + LOC(f->locale, mkname("school", magic_school[f->magiegebiet])), faction_getemail(f)); centre(out, buf, true); if (f_get_alliance(f)) { centre(out, alliancename(f->alliance), true); @@ -2088,25 +2086,30 @@ report_plaintext(const char *filename, report_context * ctx, const char *email; const char *subject; email = config_get("game.email"); - subject = get_mailcmd(f->locale); - m = msg_message("newbie_info_game", "email subject", email, subject); - if (m) { - nr_render(m, f->locale, buf, sizeof(buf), f); - msg_release(m); - centre(out, buf, true); + if (!email) + log_error("game.email not set"); + else { + subject = get_mailcmd(f->locale); + + m = msg_message("newbie_info_game", "email subject", email, subject); + if (m) { + nr_render(m, f->locale, buf, sizeof(buf), f); + msg_release(m); + centre(out, buf, true); + } } - if ((f->options & want(O_COMPUTER)) == 0) { + if ((f->options & WANT_OPTION(O_COMPUTER)) == 0) { const char *s; s = locale_getstring(f->locale, "newbie_info_cr"); if (s) { newline(out); centre(out, s, true); } - f->options |= want(O_COMPUTER); + f->options |= WANT_OPTION(O_COMPUTER); } } newline(out); - if (f->options & want(O_SCORE) && f->age > DISPLAYSCORE) { + if (f->options & WANT_OPTION(O_SCORE) && f->age > DISPLAYSCORE) { char score[32], avg[32]; write_score(score, sizeof(score), f->score); write_score(avg, sizeof(avg), average_score_of_age(f->age, f->age / 24 + 1)); @@ -2155,31 +2158,17 @@ report_plaintext(const char *filename, report_context * ctx, centre(out, buf, true); } - /* Insekten-Winter-Warnung */ - if (f->race == get_race(RC_INSECT)) { - if (thisseason == 0) { - centre(out, LOC(f->locale, "nr_insectwinter"), true); - newline(out); - } - else { - if (nextseason == 0) { - centre(out, LOC(f->locale, "nr_insectfall"), true); - newline(out); - } - } - } - bufp = buf; size = sizeof(buf) - 1; bytes = snprintf(buf, size, "%s:", LOC(f->locale, "nr_options")); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); for (op = 0; op != MAXOPTIONS; op++) { - if (f->options & want(op) && options[op]) { - bytes = (int)strlcpy(bufp, " ", size); + if (f->options & WANT_OPTION(op) && options[op]) { + bytes = (int)str_strlcpy(bufp, " ", size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(f->locale, options[op]), size); + bytes = (int)str_strlcpy(bufp, LOC(f->locale, options[op]), size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); @@ -2209,11 +2198,10 @@ report_plaintext(const char *filename, report_context * ctx, CHECK_ERRNO(); for (a = a_find(f->attribs, &at_showitem); a && a->type == &at_showitem; a = a->next) { - const potion_type *ptype = - resource2potion(((const item_type *)a->data.v)->rtype); + const item_type *itype = (const item_type *)a->data.v; const char *description = NULL; - if (ptype != NULL) { - const char *pname = resourcename(ptype->itype->rtype, 0); + if (itype) { + const char *pname = resourcename(itype->rtype, 0); if (ch == 0) { newline(out); @@ -2224,7 +2212,7 @@ report_plaintext(const char *filename, report_context * ctx, newline(out); centre(out, LOC(f->locale, pname), true); snprintf(buf, sizeof(buf), "%s %d", LOC(f->locale, "nr_level"), - ptype->level); + potion_level(itype)); centre(out, buf, true); newline(out); @@ -2234,16 +2222,16 @@ report_plaintext(const char *filename, report_context * ctx, if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); - if (ptype->itype->construction) { - requirement *m = ptype->itype->construction->materials; - while (m->number) { + if (itype->construction) { + requirement *rm = itype->construction->materials; + while (rm->number) { bytes = - (int)strlcpy(bufp, LOC(f->locale, resourcename(m->rtype, 0)), size); + (int)str_strlcpy(bufp, LOC(f->locale, resourcename(rm->rtype, 0)), size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); - ++m; - if (m->number) - bytes = (int)strlcpy(bufp, ", ", size); + ++rm; + if (rm->number) + bytes = (int)str_strlcpy(bufp, ", ", size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); } @@ -2284,7 +2272,8 @@ report_plaintext(const char *filename, report_context * ctx, if (markets_module() && r->land) { const item_type *lux = r_luxury(r); const item_type *herb = r->land->herbtype; - message *m = 0; + + m = NULL; if (herb && lux) { m = msg_message("nr_market_info_p", "p1 p2", lux->rtype, herb->rtype); @@ -2297,7 +2286,6 @@ report_plaintext(const char *filename, report_context * ctx, newline(out); nr_paragraph(out, m, f); } - /* */ } else { if (!fval(r->terrain, SEA_REGION) && rpeasants(r) / TRADE_FRACTION > 0) { @@ -2348,10 +2336,8 @@ report_plaintext(const char *filename, report_context * ctx, } } while (u && !u->ship) { - if (stealthmod > INT_MIN && r->seen.mode >= seen_unit) { - if (u->faction == f || cansee_ex(f, r, u, stealthmod, r->seen.mode)) { - nr_unit(out, f, u, 4, r->seen.mode); - } + if (visible_unit(u, f, stealthmod, r->seen.mode)) { + nr_unit(out, f, u, 4, r->seen.mode); } assert(!u->building); u = u->next; diff --git a/src/report.test.c b/src/report.test.c index 2bdbebb7c..77bb6dca6 100644 --- a/src/report.test.c +++ b/src/report.test.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -94,7 +95,7 @@ static void test_report_region(CuTest *tc) { locale_setstring(lang, "see_travel", "durchgereist"); mstream_init(&out); - r = test_create_region(0, 0, 0); + r = test_create_region(0, 0, NULL); add_resource(r, 1, 135, 10, rt_stone); CuAssertIntEquals(tc, 1, r->resources->level); r->land->peasants = 5; @@ -104,7 +105,7 @@ static void test_report_region(CuTest *tc) { rsettrees(r, 1, 2); rsettrees(r, 2, 3); region_setname(r, "Hodor"); - f = test_create_faction(0); + f = test_create_faction(NULL); f->locale = lang; u = test_create_unit(f, r); set_level(u, SK_QUARRYING, 1); @@ -138,7 +139,7 @@ static void test_report_region(CuTest *tc) { CuAssertStrEquals(tc, "Hodor (0,0), Ebene, 3/2 Blumen, 1 Stein/1, 1 Bauer, 1 Silber, 1 Pferd.\n", buf); mstream_done(&out); - test_cleanup(); + test_teardown(); } static void test_report_travelthru(CuTest *tc) { @@ -154,11 +155,11 @@ static void test_report_travelthru(CuTest *tc) { lang = get_or_create_locale("de"); locale_setstring(lang, "travelthru_header", "Durchreise: "); mstream_init(&out); - r = test_create_region(0, 0, 0); + r = test_create_region(0, 0, NULL); r->flags |= RF_TRAVELUNIT; - f = test_create_faction(0); + f = test_create_faction(NULL); f->locale = lang; - u = test_create_unit(f, test_create_region(0, 1, 0)); + u = test_create_unit(f, test_create_region(0, 1, NULL)); unit_setname(u, "Hodor"); unit_setid(u, 1); @@ -185,7 +186,7 @@ static void test_report_travelthru(CuTest *tc) { CuAssertIntEquals_Msg(tc, "do not list units that stopped in the region", 0, (int)len); mstream_done(&out); - test_cleanup(); + test_teardown(); } typedef struct { @@ -219,12 +220,11 @@ static void setup_spell_fixture(spell_fixture * spf) { static void cleanup_spell_fixture(spell_fixture *spf) { spellbook_clear(spf->spb); free(spf->spb); - test_cleanup(); } static void set_parameter(spell_fixture spell, char *value) { free(spell.sp->parameter); - spell.sp->parameter = strdup(value); + spell.sp->parameter = str_strdup(value); } static void check_spell_syntax(CuTest *tc, char *msg, spell_fixture *spell, char *syntax) { @@ -259,7 +259,7 @@ static void check_spell_syntax(CuTest *tc, char *msg, spell_fixture *spell, char static void test_write_spell_syntax(CuTest *tc) { spell_fixture spell; - test_cleanup(); + test_setup(); setup_spell_fixture(&spell); check_spell_syntax(tc, "vanilla", &spell, " ZAUBERE \"Testzauber\""); @@ -295,14 +295,14 @@ static void test_write_spell_syntax(CuTest *tc) { set_parameter(spell, "bc"); free(spell.sp->syntax); - spell.sp->syntax = strdup("hodor"); + spell.sp->syntax = str_strdup("hodor"); check_spell_syntax(tc, "bc hodor", &spell, " ZAUBERE \"Testzauber\" "); free(spell.sp->syntax); spell.sp->syntax = 0; set_parameter(spell, "c?"); free(spell.sp->syntax); - spell.sp->syntax = strdup("hodor"); + spell.sp->syntax = str_strdup("hodor"); check_spell_syntax(tc, "c?", &spell, " ZAUBERE \"Testzauber\" []"); free(spell.sp->syntax); spell.sp->syntax = 0; @@ -312,6 +312,7 @@ static void test_write_spell_syntax(CuTest *tc) { " ZAUBERE \"Testzauber\" ( REGION | EINHEIT [ ...] | SCHIFF \n [ ...] | BURG [ ...] )"); cleanup_spell_fixture(&spell); + test_teardown(); } CuSuite *get_report_suite(void) diff --git a/src/reports.c b/src/reports.c index 1591de637..602edb83c 100644 --- a/src/reports.c +++ b/src/reports.c @@ -19,6 +19,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include "reports.h" + +#include "battle.h" +#include "calendar.h" #include "guard.h" #include "laws.h" #include "spells.h" @@ -58,14 +61,17 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* util includes */ #include -#include #include +#include #include -#include #include #include #include #include +#include +#include +#include +#include #include #include @@ -164,14 +170,14 @@ size_t report_status(const unit * u, const struct locale *lang, char *fsbuf, siz struct locale *wloc = get_locale(lname); log_warning("no translation for combat status %s in %s", combatstatus[u->status], lname); locale_setstring(wloc, combatstatus[u->status], combatstatus[u->status] + 7); - len = strlcpy(fsbuf, combatstatus[u->status] + 7, buflen); + len = str_strlcpy(fsbuf, combatstatus[u->status] + 7, buflen); } else { - len = strlcpy(fsbuf, status, buflen); + len = str_strlcpy(fsbuf, status, buflen); } if (fval(u, UFL_NOAID)) { - len += strlcat(fsbuf + len, ", ", buflen - len); - len += strlcat(fsbuf + len, LOC(lang, "status_noaid"), buflen - len); + len += str_strlcat(fsbuf + len, ", ", buflen - len); + len += str_strlcat(fsbuf + len, LOC(lang, "status_noaid"), buflen - len); } return len; @@ -266,14 +272,14 @@ report_item(const unit * owner, const item * i, const faction * viewer, } #define ORDERS_IN_NR 1 -static size_t buforder(char *buffer, size_t size, const order * ord, int mode) +static size_t buforder(char *buffer, size_t size, const order * ord, const struct locale *lang, int mode) { char *bufp = buffer; bufp = STRLCPY(bufp, ", \"", size); if (mode < ORDERS_IN_NR) { char cmd[ORDERSIZE]; - get_command(ord, cmd, sizeof(cmd)); + get_command(ord, lang, cmd, sizeof(cmd)); bufp = STRLCPY(bufp, cmd, size); } else { @@ -357,25 +363,145 @@ static void report_resource(resource_report * result, const resource_type *rtype result->level = level; } -void report_race(const struct unit *u, const char **name, const char **illusion) +void report_raceinfo(const struct race *rc, const struct locale *lang, char *buf, size_t length) { - if (illusion) { - const race *irace = u_irace(u); - if (irace && irace != u_race(u)) { - *illusion = irace->_name; - } - else { - *illusion = NULL; + const char *info; + int a, at_count; + const char *name, *key; + char *bufp = buf; + size_t size = length - 1; + size_t bytes; + + name = rc_name_s(rc, NAME_SINGULAR); + + bytes = slprintf(bufp, size, "%s: ", LOC(lang, name)); + assert(bytes <= INT_MAX); + if (wrptr(&bufp, &size, (int)bytes) != 0) + WARN_STATIC_BUFFER(); + + key = mkname("raceinfo", rc->_name); + info = locale_getstring(lang, key); + if (info == NULL) { + info = LOC(lang, mkname("raceinfo", "no_info")); + } + + if (info) bufp = STRLCPY(bufp, info, size); + + /* hp_p : Trefferpunkte */ + bytes = + slprintf(bufp, size, " %d %s", rc->hitpoints, LOC(lang, + "stat_hitpoints")); + assert(bytes <= INT_MAX); + if (wrptr(&bufp, &size, (int)bytes) != 0) + WARN_STATIC_BUFFER(); + + /* b_attacke : Angriff */ + bytes = + slprintf(bufp, size, ", %s: %d", LOC(lang, "stat_attack"), + (rc->at_default + rc->at_bonus)); + assert(bytes <= INT_MAX); + if (wrptr(&bufp, &size, (int)bytes) != 0) + WARN_STATIC_BUFFER(); + + /* b_defense : Verteidigung */ + bytes = + slprintf(bufp, size, ", %s: %d", LOC(lang, "stat_defense"), + (rc->df_default + rc->df_bonus)); + assert(bytes <= INT_MAX); + if (wrptr(&bufp, &size, (int)bytes) != 0) + WARN_STATIC_BUFFER(); + + /* b_armor : Rüstung */ + if (rc->armor > 0) { + bytes = + slprintf(bufp, size, ", %s: %d", LOC(lang, "stat_armor"), rc->armor); + assert(bytes <= INT_MAX); + if (wrptr(&bufp, &size, (int)bytes) != 0) + WARN_STATIC_BUFFER(); + } + + if (size > 1) { + *bufp++ = '.'; + --size; + } + else + WARN_STATIC_BUFFER(); + + /* b_damage : Schaden */ + at_count = 0; + for (a = 0; a < RACE_ATTACKS; a++) { + if (rc->attack[a].type != AT_NONE) { + at_count++; } } - if (name) { - *name = u_race(u)->_name; - if (fval(u_race(u), RCF_SHAPESHIFTANY)) { - const char *str = get_racename(u->attribs); - if (str) - *name = str; + if (rc->battle_flags & BF_EQUIPMENT) { + if (wrptr(&bufp, &size, snprintf(bufp, size, " %s", LOC(lang, "stat_equipment"))) != 0) + WARN_STATIC_BUFFER(); + } + if (rc->battle_flags & BF_RES_PIERCE) { + if (wrptr(&bufp, &size, snprintf(bufp, size, " %s", LOC(lang, "stat_pierce"))) != 0) + WARN_STATIC_BUFFER(); + } + if (rc->battle_flags & BF_RES_CUT) { + if (wrptr(&bufp, &size, snprintf(bufp, size, " %s", LOC(lang, "stat_cut"))) != 0) + WARN_STATIC_BUFFER(); + } + if (rc->battle_flags & BF_RES_BASH) { + if (wrptr(&bufp, &size, snprintf(bufp, size, " %s", LOC(lang, "stat_bash"))) != 0) + WARN_STATIC_BUFFER(); + } + + if (wrptr(&bufp, &size, snprintf(bufp, size, " %d %s", at_count, LOC(lang, (at_count == 1) ? "stat_attack" : "stat_attacks"))) != 0) + WARN_STATIC_BUFFER(); + + for (a = 0; a < RACE_ATTACKS; a++) { + if (rc->attack[a].type != AT_NONE) { + if (a != 0) + bufp = STRLCPY(bufp, ", ", size); + else + bufp = STRLCPY(bufp, ": ", size); + + switch (rc->attack[a].type) { + case AT_STANDARD: + bytes = + (size_t)snprintf(bufp, size, "%s (%s)", + LOC(lang, "attack_standard"), rc->def_damage); + break; + case AT_NATURAL: + bytes = + (size_t)snprintf(bufp, size, "%s (%s)", + LOC(lang, "attack_natural"), rc->attack[a].data.dice); + break; + case AT_SPELL: + case AT_COMBATSPELL: + case AT_DRAIN_ST: + case AT_DRAIN_EXP: + case AT_DAZZLE: + bytes = (size_t)snprintf(bufp, size, "%s", LOC(lang, "attack_magical")); + break; + case AT_STRUCTURAL: + bytes = + (size_t)snprintf(bufp, size, "%s (%s)", + LOC(lang, "attack_structural"), rc->attack[a].data.dice); + break; + default: + bytes = 0; + } + + assert(bytes <= INT_MAX); + if (bytes && wrptr(&bufp, &size, (int)bytes) != 0) + WARN_STATIC_BUFFER(); } } + + if (size > 1) { + *bufp++ = '.'; + --size; + } + else + WARN_STATIC_BUFFER(); + + *bufp = 0; } void @@ -498,6 +624,7 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, char *bufp = buf; int result = 0; item results[MAX_INVENTORY]; + const struct locale *lang = f->locale; assert(f); bufp = STRLCPY(bufp, unitname(u), size); @@ -514,7 +641,7 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, } if (getarnt) { bufp = STRLCPY(bufp, ", ", size); - bufp = STRLCPY(bufp, LOC(f->locale, "anonymous"), size); + bufp = STRLCPY(bufp, LOC(lang, "anonymous"), size); } else if (u->attribs) { faction *otherf = get_otherfaction(u); @@ -527,16 +654,15 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, else { if (getarnt) { bufp = STRLCPY(bufp, ", ", size); - bufp = STRLCPY(bufp, LOC(f->locale, "anonymous"), size); + bufp = STRLCPY(bufp, LOC(lang, "anonymous"), size); } else { if (u->attribs && alliedunit(u, f, HELP_FSTEALTH)) { faction *otherf = get_otherfaction(u); if (otherf) { - int result = - snprintf(bufp, size, ", %s (%s)", factionname(otherf), - factionname(u->faction)); - if (wrptr(&bufp, &size, result) != 0) + int n = snprintf(bufp, size, ", %s (%s)", + factionname(otherf), factionname(u->faction)); + if (wrptr(&bufp, &size, n) != 0) WARN_STATIC_BUFFER(); } else { @@ -562,7 +688,7 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, bufp = STRLCPY(bufp, pzTmp, size); if (u->faction == f && fval(u_race(u), RCF_SHAPESHIFTANY)) { bufp = STRLCPY(bufp, " (", size); - bufp = STRLCPY(bufp, racename(f->locale, u, u_race(u)), size); + bufp = STRLCPY(bufp, racename(lang, u, u_race(u)), size); if (size > 1) { strcpy(bufp++, ")"); --size; @@ -571,10 +697,10 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, } else { const race *irace = u_irace(u); - bufp = STRLCPY(bufp, racename(f->locale, u, irace), size); + bufp = STRLCPY(bufp, racename(lang, u, irace), size); if (u->faction == f && irace != u_race(u)) { bufp = STRLCPY(bufp, " (", size); - bufp = STRLCPY(bufp, racename(f->locale, u, u_race(u)), size); + bufp = STRLCPY(bufp, racename(lang, u, u_race(u)), size); if (size > 1) { strcpy(bufp++, ")"); --size; @@ -584,15 +710,15 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, if (fval(u, UFL_HERO) && (u->faction == f || omniscient(f))) { bufp = STRLCPY(bufp, ", ", size); - bufp = STRLCPY(bufp, LOC(f->locale, "hero"), size); + bufp = STRLCPY(bufp, LOC(lang, "hero"), size); } /* status */ if (u->number && (u->faction == f || isbattle)) { const char *c = hp_status(u); - c = c ? LOC(f->locale, c) : 0; + c = c ? LOC(lang, c) : 0; bufp = STRLCPY(bufp, ", ", size); - bufp += report_status(u, f->locale, bufp, size); + bufp += report_status(u, lang, bufp, size); if (c || fval(u, UFL_HUNGER)) { bufp = STRLCPY(bufp, " (", size); if (c) { @@ -602,7 +728,7 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, if (c) { bufp = STRLCPY(bufp, ", ", size); } - bufp = STRLCPY(bufp, LOC(f->locale, "unit_hungers"), size); + bufp = STRLCPY(bufp, LOC(lang, "unit_hungers"), size); } if (size > 1) { strcpy(bufp++, ")"); @@ -612,7 +738,7 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, } if (is_guard(u)) { bufp = STRLCPY(bufp, ", ", size); - bufp = STRLCPY(bufp, LOC(f->locale, "unit_guards"), size); + bufp = STRLCPY(bufp, LOC(lang, "unit_guards"), size); } if ((b = usiege(u)) != NULL) { @@ -624,7 +750,7 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, if (u->faction == f) { skill *sv; for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { - size_t bytes = spskill(bufp, size, f->locale, u, sv, &dh, 1); + size_t bytes = spskill(bufp, size, lang, u, sv, &dh, 1); assert(bytes <= INT_MAX); if (wrptr(&bufp, &size, (int)bytes) != 0) WARN_STATIC_BUFFER(); @@ -651,7 +777,7 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, bufp = STRLCPY(bufp, ", ", size); if (!dh) { - result = snprintf(bufp, size, "%s: ", LOC(f->locale, "nr_inventory")); + result = snprintf(bufp, size, "%s: ", LOC(lang, "nr_inventory")); if (wrptr(&bufp, &size, result) != 0) WARN_STATIC_BUFFER(); dh = 1; @@ -671,27 +797,26 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, if (book) { selist *ql = book->spells; int qi, header, maxlevel = effskill(u, SK_MAGIC, 0); - int result = snprintf(bufp, size, ". Aura %d/%d", get_spellpoints(u), max_spellpoints(u->region, u)); - if (wrptr(&bufp, &size, result) != 0) { + int n = snprintf(bufp, size, ". Aura %d/%d", get_spellpoints(u), max_spellpoints(u->region, u)); + if (wrptr(&bufp, &size, n) != 0) { WARN_STATIC_BUFFER(); } for (header = 0, qi = 0; ql; selist_advance(&ql, &qi, 1)) { spellbook_entry * sbe = (spellbook_entry *)selist_get(ql, qi); if (sbe->level <= maxlevel) { - int result = 0; if (!header) { - result = snprintf(bufp, size, ", %s: ", LOC(f->locale, "nr_spells")); + n = snprintf(bufp, size, ", %s: ", LOC(lang, "nr_spells")); header = 1; } else { - result = (int)strlcpy(bufp, ", ", size); + n = (int)str_strlcpy(bufp, ", ", size); } - if (wrptr(&bufp, &size, result) != 0) { + if (wrptr(&bufp, &size, n) != 0) { WARN_STATIC_BUFFER(); } /* TODO: no need to deref the spellref here (spref->name is good) */ - bufp = STRLCPY(bufp, spell_name(sbe->sp, f->locale), size); + bufp = STRLCPY(bufp, spell_name(sbe->sp, lang), size); } } @@ -700,9 +825,8 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, break; } if (i != MAXCOMBATSPELLS) { - int result = - snprintf(bufp, size, ", %s: ", LOC(f->locale, "nr_combatspells")); - if (wrptr(&bufp, &size, result) != 0) + n = snprintf(bufp, size, ", %s: ", LOC(lang, "nr_combatspells")); + if (wrptr(&bufp, &size, n) != 0) WARN_STATIC_BUFFER(); dh = 0; @@ -717,15 +841,15 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, sp = get_combatspell(u, i); if (sp) { int sl = get_combatspelllevel(u, i); - bufp = STRLCPY(bufp, spell_name(sp, u->faction->locale), size); + bufp = STRLCPY(bufp, spell_name(sp, lang), size); if (sl > 0) { - result = snprintf(bufp, size, " (%d)", sl); - if (wrptr(&bufp, &size, result) != 0) + n = snprintf(bufp, size, " (%d)", sl); + if (wrptr(&bufp, &size, n) != 0) WARN_STATIC_BUFFER(); } } else { - bufp = STRLCPY(bufp, LOC(f->locale, "nr_nospells"), size); + bufp = STRLCPY(bufp, LOC(lang, "nr_nospells"), size); } } } @@ -737,8 +861,8 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, keyword_t kwd = getkeyword(ord); if (is_repeated(kwd)) { if (printed < ORDERS_IN_NR) { - int result = (int)buforder(bufp, size, ord, printed++); - if (wrptr(&bufp, &size, result) != 0) + int n = (int)buforder(bufp, size, ord, u->faction->locale, printed++); + if (wrptr(&bufp, &size, n) != 0) WARN_STATIC_BUFFER(); } else @@ -750,19 +874,20 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, keyword_t kwd = getkeyword(ord); if (is_repeated(kwd)) { if (printed < ORDERS_IN_NR) { - int result = (int)buforder(bufp, size, ord, printed++); - if (wrptr(&bufp, &size, result) != 0) + int n = (int)buforder(bufp, size, ord, lang, printed++); + if (wrptr(&bufp, &size, n) != 0) WARN_STATIC_BUFFER(); } - else + else { break; + } } } } } i = 0; - str = u_description(u, f->locale); + str = u_description(u, lang); if (str) { bufp = STRLCPY(bufp, "; ", size); bufp = STRLCPY(bufp, str, size); @@ -803,7 +928,7 @@ spskill(char *buffer, size_t size, const struct locale * lang, if (!u->number) return 0; if (sv->level <= 0) { - if (sv->old <= 0 || (u->faction->options & want(O_SHOWSKCHANGE)) == 0) { + if (sv->old <= 0 || (u->faction->options & WANT_OPTION(O_SHOWSKCHANGE)) == 0) { return 0; } } @@ -839,7 +964,7 @@ spskill(char *buffer, size_t size, const struct locale * lang, if (wrptr(&bufp, &size, snprintf(bufp, size, "%d", effsk)) != 0) WARN_STATIC_BUFFER(); - if (u->faction->options & want(O_SHOWSKCHANGE)) { + if (u->faction->options & WANT_OPTION(O_SHOWSKCHANGE)) { int oldeff = 0; int diff; @@ -948,10 +1073,10 @@ struct message *msg_curse(const struct curse *c, const void *obj, objtype_t typ, { "unit_unknown", "region_unknown", "building_unknown", "ship_unknown" }; msg = msg_message(mkname("curseinfo", unknown[typ]), "id", c->no); - log_error("no curseinfo function for %s and no fallback either.\n", c->type->cname); + log_warning("no curseinfo function for %s and no fallback either.\n", c->type->cname); } else { - log_error("no curseinfo function for %s, using cinfo_simple fallback.\n", c->type->cname); + log_debug("no curseinfo function for %s, using cinfo_simple fallback.\n", c->type->cname); } return msg; } @@ -1335,8 +1460,8 @@ void reorder_units(region * r) while (*unext && sh) { unit **ufirst = unext; /* where the first unit in the building should go */ - unit **umove = unext; /* a unit we consider moving */ unit *owner = ship_owner(sh); + umove = unext; while (owner && *umove) { unit *u = *umove; if (u->number && u->ship == sh) { @@ -1395,6 +1520,29 @@ static void cb_add_seen(region *r, unit *u, void *cbdata) { } } +void report_warnings(faction *f, const gamedate *date) +{ + if (f->age < NewbieImmunity()) { + ADDMSG(&f->msgs, msg_message("newbieimmunity", "turns", + NewbieImmunity() - f->age)); + } + + if (date) { + if (f->race == get_race(RC_INSECT)) { + if (date->season == 0) { + ADDMSG(&f->msgs, msg_message("nr_insectwinter", "")); + } + else { + gamedate next; + get_gamedate(date->turn + 1, &next); + if (next.season == 0) { + ADDMSG(&f->msgs, msg_message("nr_insectfall", "")); + } + } + } + } +} + /** set region.seen based on visibility by one faction. * * this function may also update ctx->last and ctx->first for potential @@ -1407,6 +1555,11 @@ void prepare_report(report_context *ctx, faction *f) static bool rule_region_owners; static bool rule_lighthouse_units; const struct building_type *bt_lighthouse = bt_find("lighthouse"); + gamedate now; + + /* Insekten-Winter-Warnung */ + get_gamedate(turn, &now); + report_warnings(f, &now); if (bt_lighthouse && config_changed(&config)) { rule_region_owners = config_token("rules.region_owner_pay_building", bt_lighthouse->_name); @@ -1446,8 +1599,8 @@ void prepare_report(report_context *ctx, faction *f) for (b = rbuildings(r); b; b = b->next) { if (b && b->type == bt_lighthouse) { /* region owners get maximm range */ - int br = lighthouse_range(b, NULL, NULL); - if (br > range) range = br; + int lhr = lighthouse_range(b, NULL, NULL); + if (lhr > range) range = lhr; } } } @@ -1536,7 +1689,7 @@ int write_reports(faction * f, time_t ltime) char path[4096]; sprintf(filename, "%d-%s.%s", turn, itoa36(f->no), rtype->extension); - join_path(reportpath(), filename, path, sizeof(path)); + path_join(reportpath(), filename, path, sizeof(path)); errno = 0; if (rtype->write(path, &ctx, (const char *)utf8_bom) == 0) { gotit = true; @@ -1560,8 +1713,12 @@ static void write_script(FILE * F, const faction * f) { report_type *rtype; char buf[1024]; - - fprintf(F, "faction=%s:email=%s:lang=%s", itoa36(f->no), f->email, + + if (check_email(faction_getemail(f)) != 0) { + return; + } + + fprintf(F, "faction=%s:email=%s:lang=%s", itoa36(f->no), faction_getemail(f), locale_name(f->locale)); if (f->options & (1 << O_BZIP2)) fputs(":compression=bz2", F); @@ -1573,9 +1730,9 @@ static void write_script(FILE * F, const faction * f) for (rtype = report_types; rtype != NULL; rtype = rtype->next) { if (f->options & rtype->flag) { if (buf[0]) { - strlcat(buf, ",", sizeof(buf)); + str_strlcat(buf, ",", sizeof(buf)); } - strlcat(buf, rtype->extension, sizeof(buf)); + str_strlcat(buf, rtype->extension, sizeof(buf)); } } fputs(buf, F); @@ -1610,7 +1767,7 @@ int reports(void) report_donations(); remove_empty_units(); - join_path(rpath, "reports.txt", path, sizeof(path)); + path_join(rpath, "reports.txt", path, sizeof(path)); mailit = fopen(path, "w"); if (mailit == NULL) { log_error("%s could not be opened!\n", path); @@ -1632,7 +1789,7 @@ int reports(void) static variant var_copy_string(variant x) { - x.v = x.v ? strdup((const char *)x.v) : 0; + x.v = x.v ? str_strdup((const char *)x.v) : 0; return x; } @@ -1710,8 +1867,8 @@ const char *trailinto(const region * r, const struct locale *lang) const char *tname = terrain_name(r); size_t sz; - sz = strlcpy(ref, tname, sizeof(ref)); - sz += strlcat(ref + sz, "_trail", sizeof(ref) - sz); + sz = str_strlcpy(ref, tname, sizeof(ref)); + sz += str_strlcat(ref + sz, "_trail", sizeof(ref) - sz); s = LOC(lang, ref); if (s && *s) { if (strstr(s, "%s")) @@ -1726,7 +1883,7 @@ f_regionid(const region * r, const faction * f, char *buffer, size_t size) { size_t len; if (!r) { - len = strlcpy(buffer, "(Chaos)", size); + len = str_strlcpy(buffer, "(Chaos)", size); } else { plane *pl = rplane(r); @@ -1735,7 +1892,7 @@ f_regionid(const region * r, const faction * f, char *buffer, size_t size) int named = (name && name[0]); pnormalize(&nx, &ny, pl); adjust_coordinates(f, &nx, &ny, pl); - len = strlcpy(buffer, rname(r, f ? f->locale : 0), size); + len = str_strlcpy(buffer, rname(r, f ? f->locale : 0), size); snprintf(buffer + len, size - len, " (%d,%d%s%s)", nx, ny, named ? "," : "", (named) ? name : ""); buffer[size - 1] = 0; len = strlen(buffer); @@ -1980,22 +2137,72 @@ static void eval_race(struct opstack **stack, const void *userdata) static void eval_order(struct opstack **stack, const void *userdata) { /* order -> string */ + const faction *f = (const faction *)userdata; const struct order *ord = (const struct order *)opop(stack).v; char buf[4096]; size_t len; variant var; + const struct locale *lang = f ? f->locale : default_locale; UNUSED_ARG(userdata); - write_order(ord, buf, sizeof(buf)); + write_order(ord, lang, buf, sizeof(buf)); len = strlen(buf); var.v = strcpy(balloc(len + 1), buf); opush(stack, var); } +void report_battle_start(battle * b) +{ + bfaction *bf; + char zText[32 * MAXSIDES]; + sbstring sbs; + + for (bf = b->factions; bf; bf = bf->next) { + message *m; + faction *f = bf->faction; + const char *lastf = NULL; + bool first = false; + side *s; + + sbs_init(&sbs, zText, sizeof(zText)); + for (s = b->sides; s != b->sides + b->nsides; ++s) { + fighter *df; + for (df = s->fighters; df; df = df->next) { + if (is_attacker(df)) { + if (first) { + sbs_strcpy(&sbs, ", "); + } + if (lastf) { + sbs_strcpy(&sbs, lastf); + first = true; + } + if (seematrix(f, s)) + lastf = sidename(s); + else + lastf = LOC(f->locale, "unknown_faction_dative"); + break; + } + } + } + if (first) { + sbs_strcat(&sbs, " "); + sbs_strcat(&sbs, LOC(f->locale, "and")); + sbs_strcat(&sbs, " "); + } + if (lastf) { + sbs_strcat(&sbs, lastf); + } + + m = msg_message("start_battle", "factions", zText); + battle_message_faction(b, f, m); + msg_release(m); + } +} + static void eval_resources(struct opstack **stack, const void *userdata) { /* order -> string */ - const faction *report = (const faction *)userdata; - const struct locale *lang = report ? report->locale : default_locale; + const faction *f = (const faction *)userdata; + const struct locale *lang = f ? f->locale : default_locale; const struct resource *res = (const struct resource *)opop(stack).v; char buf[1024]; /* but we only use about half of this */ size_t size = sizeof(buf) - 1; @@ -2108,6 +2315,42 @@ static void eval_trail(struct opstack **stack, const void *userdata) #endif } +void report_race_skills(const race *rc, char *zText, size_t length, const struct locale *lang) +{ + size_t size = length - 1; + int dh = 0, dh1 = 0, sk; + char *bufp = zText; + + for (sk = 0; sk < MAXSKILLS; ++sk) { + if (skill_enabled(sk) && rc->bonus[sk] > -5) + dh++; + } + + for (sk = 0; sk < MAXSKILLS; sk++) { + if (skill_enabled(sk) && rc->bonus[sk] > -5) { + size_t bytes; + dh--; + if (dh1 == 0) { + dh1 = 1; + } + else { + if (dh == 0) { + bytes = str_strlcpy(bufp, LOC(lang, "list_and"), size); + } + else { + bytes = str_strlcpy(bufp, ", ", size); + } + assert(bytes <= INT_MAX); + BUFFER_STRCAT(bufp, size, bytes); + } + bytes = str_strlcpy(bufp, skillname((skill_t)sk, lang), + size); + assert(bytes <= INT_MAX); + BUFFER_STRCAT(bufp, size, (int)bytes); + } + } +} + static void eval_direction(struct opstack **stack, const void *userdata) { const faction *report = (const faction *)userdata; @@ -2188,6 +2431,19 @@ int count_travelthru(struct region *r, const struct faction *f) { return data.n; } +bool visible_unit(const unit *u, const faction *f, int stealthmod, seen_mode mode) +{ + if (u->faction == f) { + return true; + } + else { + if (stealthmod > INT_MIN && mode >= seen_unit) { + return cansee(f, u->region, u, stealthmod); + } + } + return false; +} + void register_reports(void) { /* register datatypes for the different message objects */ diff --git a/src/reports.h b/src/reports.h index a4850a0c7..0c285257e 100644 --- a/src/reports.h +++ b/src/reports.h @@ -29,6 +29,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif + struct battle; + struct gamedate; struct selist; struct stream; struct seen_region; @@ -96,6 +98,7 @@ extern "C" { const struct locale *lang); size_t report_status(const struct unit *u, const struct locale *lang, char *buf, size_t siz); + void report_battle_start(struct battle * b); void register_reports(void); @@ -116,14 +119,14 @@ extern "C" { int size, const struct faction *viewer, bool see_unit); int report_items(const struct unit *u, struct item *result, int size, const struct unit *owner, const struct faction *viewer); + void report_warnings(struct faction *f, const struct gamedate *date); + void report_raceinfo(const struct race *rc, const struct locale *lang, char *buf, size_t length); + void report_race_skills(const struct race *rc, char *zText, size_t length, const struct locale *lang); void report_item(const struct unit *owner, const struct item *i, const struct faction *viewer, const char **name, const char **basename, int *number, bool singular); void report_building(const struct building *b, const char **btype, const char **billusion); - void report_race(const struct unit *u, const char **rcname, - const char **rcillusion); - void add_seen_faction(struct faction *self, struct faction *seen); size_t f_regionid(const struct region *r, const struct faction *f, char *buffer, size_t size); @@ -135,6 +138,8 @@ extern "C" { int count_travelthru(struct region *r, const struct faction *f); const char *get_mailcmd(const struct locale *loc); + bool visible_unit(const struct unit *u, const struct faction *f, int stealthmod, seen_mode mode); + #define GR_PLURAL 0x01 /* grammar: plural */ #define MAX_INVENTORY 128 /* maimum number of different items in an inventory */ #define MAX_RAWMATERIALS 8 /* maximum kinds of raw materials in a regions */ diff --git a/src/reports.test.c b/src/reports.test.c index 0c9cf2b78..ca0f98f57 100644 --- a/src/reports.test.c +++ b/src/reports.test.c @@ -1,12 +1,14 @@ #include #include "reports.h" +#include "calendar.h" +#include "keyword.h" +#include "lighthouse.h" +#include "laws.h" #include "move.h" +#include "spells.h" #include "spy.h" -#include "lighthouse.h" #include "travelthru.h" -#include "keyword.h" -#include "spells.h" #include #include @@ -52,7 +54,7 @@ static void test_reorder_units(CuTest * tc) r = test_create_region(0, 0, NULL); b = test_create_building(r, NULL); s = test_create_ship(r, NULL); - f = test_create_faction(0); + f = test_create_faction(NULL); u0 = test_create_unit(f, r); u_set_ship(u0, s); @@ -74,7 +76,7 @@ static void test_reorder_units(CuTest * tc) CuAssertPtrEquals(tc, u1, u2->next); CuAssertPtrEquals(tc, u0, u1->next); CuAssertPtrEquals(tc, 0, u0->next); - test_cleanup(); + test_teardown(); } static void test_regionid(CuTest * tc) { @@ -83,7 +85,7 @@ static void test_regionid(CuTest * tc) { struct region * r; char buffer[64]; - test_cleanup(); + test_setup(); plain = test_create_terrain("plain", 0); r = test_create_region(0, 0, plain); @@ -97,14 +99,14 @@ static void test_regionid(CuTest * tc) { CuAssertIntEquals(tc, 10, (int)len); CuAssertStrEquals(tc, "plain (0,0", buffer); CuAssertIntEquals(tc, 0x7d, buffer[11]); - test_cleanup(); + test_teardown(); } static void test_seen_faction(CuTest *tc) { faction *f1, *f2; race *rc; - test_cleanup(); + test_setup(); rc = test_create_race("human"); f1 = test_create_faction(rc); f2 = test_create_faction(rc); @@ -118,7 +120,7 @@ static void test_seen_faction(CuTest *tc) { f2 = (faction *)selist_get(f1->seen_factions, 1); f1 = (faction *)selist_get(f1->seen_factions, 0); CuAssertTrue(tc, f1->no < f2->no); - test_cleanup(); + test_teardown(); } static void test_sparagraph(CuTest *tc) { @@ -182,11 +184,11 @@ static void test_bufunit_fstealth(CuTest *tc) { lang = get_or_create_locale("de"); locale_setstring(lang, "status_aggressive", "aggressive"); locale_setstring(lang, "anonymous", "anonymous"); - f1 = test_create_faction(0); + f1 = test_create_faction(NULL); f1->locale = lang; - f2 = test_create_faction(0); + f2 = test_create_faction(NULL); f2->locale = lang; - r = test_create_region(0, 0, 0); + r = test_create_region(0, 0, NULL); u = test_create_unit(f1, r); faction_setname(f1, "UFO"); renumber_faction(f1, 1); @@ -250,7 +252,7 @@ static void test_bufunit_fstealth(CuTest *tc) { CuAssertStrEquals(tc, "Hodor (1), anonymous, 1 human.", buf); u->flags &= ~UFL_ANON_FACTION; - test_cleanup(); + test_teardown(); } static void test_bufunit(CuTest *tc) { @@ -269,7 +271,7 @@ static void test_bufunit(CuTest *tc) { locale_setstring(lang, "skill::alchemy", "Alchemie"); locale_setstring(lang, "status_aggressive", "aggressiv"); init_skills(lang); - u = test_create_unit(test_create_faction(rc), test_create_region(0, 0, 0)); + u = test_create_unit(test_create_faction(rc), test_create_region(0, 0, NULL)); u->faction->locale = lang; faction_setname(u->faction, "UFO"); renumber_faction(u->faction, 1); @@ -287,12 +289,12 @@ static void test_bufunit(CuTest *tc) { bufunit(u->faction, u, 0, 0, buffer, sizeof(buffer)); CuAssertStrEquals(tc, "Hodor (1), 1 human, aggressiv, Talente: Alchemie 2, Segeln 1.", buffer); - f = test_create_faction(0); + f = test_create_faction(NULL); f->locale = get_or_create_locale("de"); bufunit(f, u, 0, 0, buffer, sizeof(buffer)); CuAssertStrEquals(tc, "Hodor (1), UFO (1), 1 human.", buffer); - test_cleanup(); + test_teardown(); } static void test_arg_resources(CuTest *tc) { @@ -325,14 +327,14 @@ static void test_arg_resources(CuTest *tc) { CuAssertIntEquals(tc, 5, res->number); CuAssertPtrEquals(tc, 0, res->next); atype->release(v2); - test_cleanup(); + test_teardown(); } static void test_newbie_password_message(CuTest *tc) { report_context ctx; faction *f; test_setup(); - f = test_create_faction(0); + f = test_create_faction(NULL); f->age = 5; f->flags = 0; prepare_report(&ctx, f); @@ -343,7 +345,7 @@ static void test_newbie_password_message(CuTest *tc) { CuAssertIntEquals(tc, FFL_PWMSG, f->flags&FFL_PWMSG); CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "changepasswd")); finish_reports(&ctx); - test_cleanup(); + test_teardown(); } static void test_prepare_travelthru(CuTest *tc) { @@ -353,9 +355,9 @@ static void test_prepare_travelthru(CuTest *tc) { unit *u; test_setup(); - f = test_create_faction(0); - f2 = test_create_faction(0); - r1 = test_create_region(0, 0, 0); + f = test_create_faction(NULL); + f2 = test_create_faction(NULL); + r1 = test_create_region(0, 0, NULL); r2 = test_create_region(1, 0, 0); r3 = test_create_region(3, 0, 0); test_create_unit(f2, r1); @@ -380,7 +382,7 @@ static void test_prepare_travelthru(CuTest *tc) { CuAssertPtrEquals(tc, r1, ctx.first); CuAssertPtrEquals(tc, NULL, ctx.last); finish_reports(&ctx); - test_cleanup(); + test_teardown(); } static void test_get_addresses(CuTest *tc) { @@ -389,10 +391,10 @@ static void test_get_addresses(CuTest *tc) { region *r; test_setup(); - f = test_create_faction(0); - f1 = test_create_faction(0); - f2 = test_create_faction(0); - r = test_create_region(0, 0, 0); + f = test_create_faction(NULL); + f1 = test_create_faction(NULL); + f2 = test_create_faction(NULL); + r = test_create_region(0, 0, NULL); test_create_unit(f, r); test_create_unit(f1, r); test_create_unit(f2, r); @@ -406,7 +408,7 @@ static void test_get_addresses(CuTest *tc) { CuAssertTrue(tc, selist_contains(ctx.addresses, f2, NULL)); CuAssertIntEquals(tc, 3, selist_length(ctx.addresses)); finish_reports(&ctx); - test_cleanup(); + test_teardown(); } static void test_get_addresses_fstealth(CuTest *tc) { @@ -416,10 +418,10 @@ static void test_get_addresses_fstealth(CuTest *tc) { unit *u; test_setup(); - f = test_create_faction(0); - f1 = test_create_faction(0); - f2 = test_create_faction(0); - r = test_create_region(0, 0, 0); + f = test_create_faction(NULL); + f1 = test_create_faction(NULL); + f2 = test_create_faction(NULL); + r = test_create_region(0, 0, NULL); test_create_unit(f, r); u = test_create_unit(f1, r); set_factionstealth(u, f2); @@ -434,7 +436,7 @@ static void test_get_addresses_fstealth(CuTest *tc) { CuAssertTrue(tc, selist_contains(ctx.addresses, f2, NULL)); CuAssertIntEquals(tc, 2, selist_length(ctx.addresses)); finish_reports(&ctx); - test_cleanup(); + test_teardown(); } static void test_get_addresses_travelthru(CuTest *tc) { @@ -444,10 +446,10 @@ static void test_get_addresses_travelthru(CuTest *tc) { unit *u; test_setup(); - f = test_create_faction(0); - f1 = test_create_faction(0); - f2 = test_create_faction(0); - r1 = test_create_region(0, 0, 0); + f = test_create_faction(NULL); + f1 = test_create_faction(NULL); + f2 = test_create_faction(NULL); + r1 = test_create_region(0, 0, NULL); r2 = test_create_region(1, 0, 0); u = test_create_unit(f, r2); travelthru_add(r1, u); @@ -465,7 +467,7 @@ static void test_get_addresses_travelthru(CuTest *tc) { CuAssertTrue(tc, selist_contains(ctx.addresses, f2, NULL)); CuAssertIntEquals(tc, 2, selist_length(ctx.addresses)); finish_reports(&ctx); - test_cleanup(); + test_teardown(); } void test_prepare_lighthouse_capacity(CuTest *tc) { @@ -478,7 +480,7 @@ void test_prepare_lighthouse_capacity(CuTest *tc) { report_context ctx; test_setup(); - f = test_create_faction(0); + f = test_create_faction(NULL); t_ocean = test_create_terrain("ocean", SEA_REGION); t_plain = test_create_terrain("plain", LAND_REGION); btype = test_create_buildingtype("lighthouse"); @@ -489,7 +491,7 @@ void test_prepare_lighthouse_capacity(CuTest *tc) { b->flags |= BLD_MAINTAINED; b->size = 10; update_lighthouse(b); - u1 = test_create_unit(test_create_faction(0), r1); + u1 = test_create_unit(test_create_faction(NULL), r1); u1->number = 4; u1->building = b; set_level(u1, SK_PERCEPTION, 3); @@ -522,7 +524,7 @@ void test_prepare_lighthouse_capacity(CuTest *tc) { CuAssertIntEquals(tc, seen_lighthouse, r2->seen.mode); finish_reports(&ctx); - test_cleanup(); + test_teardown(); } static void test_prepare_lighthouse(CuTest *tc) { @@ -537,7 +539,7 @@ static void test_prepare_lighthouse(CuTest *tc) { test_setup(); t_ocean = test_create_terrain("ocean", SEA_REGION); t_plain = test_create_terrain("plain", LAND_REGION); - f = test_create_faction(0); + f = test_create_faction(NULL); r1 = test_create_region(0, 0, t_plain); r2 = test_create_region(1, 0, t_ocean); r3 = test_create_region(2, 0, t_ocean); @@ -556,7 +558,7 @@ static void test_prepare_lighthouse(CuTest *tc) { CuAssertIntEquals(tc, seen_lighthouse, r2->seen.mode); CuAssertIntEquals(tc, seen_neighbour, r3->seen.mode); finish_reports(&ctx); - test_cleanup(); + test_teardown(); } /** @@ -579,7 +581,7 @@ static void test_prepare_lighthouse_owners(CuTest *tc) config_set("rules.region_owners", "1"); t_ocean = test_create_terrain("ocean", SEA_REGION); t_plain = test_create_terrain("plain", LAND_REGION); - f = test_create_faction(0); + f = test_create_faction(NULL); r1 = test_create_region(0, 0, t_plain); r2 = test_create_region(1, 0, t_ocean); r3 = test_create_region(2, 0, t_ocean); @@ -590,7 +592,7 @@ static void test_prepare_lighthouse_owners(CuTest *tc) b->size = 10; update_lighthouse(b); u = test_create_unit(f, r1); - u = test_create_unit(test_create_faction(0), r1); + u = test_create_unit(test_create_faction(NULL), r1); u->building = b; region_set_owner(b->region, f, 0); CuAssertIntEquals(tc, 2, lighthouse_range(b, NULL, NULL)); @@ -601,7 +603,7 @@ static void test_prepare_lighthouse_owners(CuTest *tc) CuAssertIntEquals(tc, seen_lighthouse, r2->seen.mode); CuAssertIntEquals(tc, seen_neighbour, r3->seen.mode); finish_reports(&ctx); - test_cleanup(); + test_teardown(); } static void test_prepare_report(CuTest *tc) { @@ -610,8 +612,8 @@ static void test_prepare_report(CuTest *tc) { region *r; test_setup(); - f = test_create_faction(0); - r = test_create_region(0, 0, 0); + f = test_create_faction(NULL); + r = test_create_region(0, 0, NULL); prepare_report(&ctx, f); CuAssertPtrEquals(tc, 0, ctx.first); @@ -634,7 +636,7 @@ static void test_prepare_report(CuTest *tc) { CuAssertPtrEquals(tc, r, ctx.last); CuAssertIntEquals(tc, seen_none, r->seen.mode); finish_reports(&ctx); - test_cleanup(); + test_teardown(); } static void test_seen_neighbours(CuTest *tc) { @@ -643,8 +645,8 @@ static void test_seen_neighbours(CuTest *tc) { region *r1, *r2; test_setup(); - f = test_create_faction(0); - r1 = test_create_region(0, 0, 0); + f = test_create_faction(NULL); + r1 = test_create_region(0, 0, NULL); r2 = test_create_region(1, 0, 0); test_create_unit(f, r1); @@ -654,7 +656,7 @@ static void test_seen_neighbours(CuTest *tc) { CuAssertIntEquals(tc, seen_unit, r1->seen.mode); CuAssertIntEquals(tc, seen_neighbour, r2->seen.mode); finish_reports(&ctx); - test_cleanup(); + test_teardown(); } static void test_seen_travelthru(CuTest *tc) { @@ -664,8 +666,8 @@ static void test_seen_travelthru(CuTest *tc) { region *r1, *r2, *r3; test_setup(); - f = test_create_faction(0); - r1 = test_create_region(0, 0, 0); + f = test_create_faction(NULL); + r1 = test_create_region(0, 0, NULL); r2 = test_create_region(1, 0, 0); r3 = test_create_region(2, 0, 0); @@ -682,7 +684,7 @@ static void test_seen_travelthru(CuTest *tc) { CuAssertIntEquals(tc, seen_travel, r2->seen.mode); CuAssertIntEquals(tc, seen_neighbour, r3->seen.mode); finish_reports(&ctx); - test_cleanup(); + test_teardown(); } static void test_region_distance_max(CuTest *tc) { @@ -690,7 +692,7 @@ static void test_region_distance_max(CuTest *tc) { region *result[64]; int x, y; test_setup(); - r = test_create_region(0, 0, 0); + r = test_create_region(0, 0, NULL); for (x=-3;x<=3;++x) { for (y = -3; y <= 3; ++y) { if (x != 0 || y != 0) { @@ -702,14 +704,14 @@ static void test_region_distance_max(CuTest *tc) { CuAssertIntEquals(tc, 7, get_regions_distance_arr(r, 1, result, 64)); CuAssertIntEquals(tc, 19, get_regions_distance_arr(r, 2, result, 64)); CuAssertIntEquals(tc, 37, get_regions_distance_arr(r, 3, result, 64)); - test_cleanup(); + test_teardown(); } static void test_region_distance(CuTest *tc) { region *r; region *result[8]; test_setup(); - r = test_create_region(0, 0, 0); + r = test_create_region(0, 0, NULL); CuAssertIntEquals(tc, 1, get_regions_distance_arr(r, 0, result, 8)); CuAssertPtrEquals(tc, r, result[0]); CuAssertIntEquals(tc, 1, get_regions_distance_arr(r, 1, result, 8)); @@ -718,14 +720,14 @@ static void test_region_distance(CuTest *tc) { CuAssertIntEquals(tc, 1, get_regions_distance_arr(r, 0, result, 8)); CuAssertIntEquals(tc, 3, get_regions_distance_arr(r, 1, result, 8)); CuAssertIntEquals(tc, 3, get_regions_distance_arr(r, 2, result, 8)); - test_cleanup(); + test_teardown(); } static void test_region_distance_ql(CuTest *tc) { region *r; selist *ql; test_setup(); - r = test_create_region(0, 0, 0); + r = test_create_region(0, 0, NULL); ql = get_regions_distance(r, 0); CuAssertIntEquals(tc, 1, selist_length(ql)); CuAssertPtrEquals(tc, r, selist_get(ql, 0)); @@ -738,15 +740,15 @@ static void test_region_distance_ql(CuTest *tc) { ql = get_regions_distance(r, 2); CuAssertIntEquals(tc, 3, selist_length(ql)); selist_free(ql); - test_cleanup(); + test_teardown(); } static void test_report_far_vision(CuTest *tc) { faction *f; region *r1, *r2; test_setup(); - f = test_create_faction(0); - r1 = test_create_region(0, 0, 0); + f = test_create_faction(NULL); + r1 = test_create_region(0, 0, NULL); test_create_unit(f, r1); r2 = test_create_region(10, 0, 0); set_observer(r2, f, 10, 2); @@ -759,7 +761,7 @@ static void test_report_far_vision(CuTest *tc) { CuAssertIntEquals(tc, seen_unit, r1->seen.mode); CuAssertIntEquals(tc, seen_spell, r2->seen.mode); finish_reports(&ctx); - test_cleanup(); + test_teardown(); } static void test_stealth_modifier(CuTest *tc) { @@ -777,7 +779,69 @@ static void test_stealth_modifier(CuTest *tc) { set_observer(r, f, 10, 1); CuAssertIntEquals(tc, 10, stealth_modifier(r, f, seen_spell)); CuAssertIntEquals(tc, -1, stealth_modifier(r, NULL, seen_spell)); - test_cleanup(); + test_teardown(); +} + +static void test_insect_warnings(CuTest *tc) { + faction *f; + gamedate gd; + + /* OBS: in unit tests, get_gamedate always returns season = 0 */ + test_setup(); + test_inject_messagetypes(); + f = test_create_faction(test_create_race("insect")); + + gd.turn = 0; + gd.season = 3; + report_warnings(f, &gd); + CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "nr_insectfall")); + + gd.season = 0; + report_warnings(f, &gd); + CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "nr_insectwinter")); + test_teardown(); +} + +static void test_newbie_warning(CuTest *tc) { + faction *f; + + test_setup(); + test_inject_messagetypes(); + f = test_create_faction(test_create_race("insect")); + config_set_int("NewbieImmunity", 3); + + f->age = 2; + report_warnings(f, NULL); + CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "newbieimmunity")); + test_clear_messages(f); + + f->age = 3; + report_warnings(f, NULL); + CuAssertPtrEquals(tc, NULL, test_find_messagetype(f->msgs, "newbieimmunity")); + test_clear_messages(f); + + test_teardown(); +} + +static void test_cansee_spell(CuTest *tc) { + unit *u2; + faction *f; + + test_setup(); + f = test_create_faction(NULL); + u2 = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); + + CuAssertTrue(tc, cansee(f, u2->region, u2, 0)); + CuAssertTrue(tc, visible_unit(u2, f, 0, seen_spell)); + CuAssertTrue(tc, visible_unit(u2, f, 0, seen_battle)); + + set_level(u2, SK_STEALTH, 1); + CuAssertTrue(tc, !cansee(f, u2->region, u2, 0)); + CuAssertTrue(tc, cansee(f, u2->region, u2, 1)); + CuAssertTrue(tc, visible_unit(u2, f, 1, seen_spell)); + CuAssertTrue(tc, visible_unit(u2, f, 1, seen_battle)); + + test_teardown(); } CuSuite *get_reports_suite(void) @@ -807,5 +871,8 @@ CuSuite *get_reports_suite(void) SUITE_ADD_TEST(suite, test_bufunit); SUITE_ADD_TEST(suite, test_bufunit_fstealth); SUITE_ADD_TEST(suite, test_arg_resources); + SUITE_ADD_TEST(suite, test_insect_warnings); + SUITE_ADD_TEST(suite, test_newbie_warning); + SUITE_ADD_TEST(suite, test_cansee_spell); return suite; } diff --git a/src/settings.h b/src/settings.h index e8693a763..0a017dd7a 100644 --- a/src/settings.h +++ b/src/settings.h @@ -24,12 +24,6 @@ #define ROW_FACTOR 3 /* factor for combat row advancement rule */ -/* optional game components. TODO: These should either be - * configuration variables (XML), script extensions (lua), - * or both. We don't want separate binaries for different games - */ -#define MUSEUM_MODULE 1 - /* TODO: move these settings to settings.h or into configuration files */ #define TREESIZE (8) /* space used by trees (in #peasants) */ #define PEASANTFORCE 0.75 /* Chance einer Vermehrung trotz 90% Auslastung */ diff --git a/src/skill.test.c b/src/skill.test.c index 9da795d0a..abfe529f9 100644 --- a/src/skill.test.c +++ b/src/skill.test.c @@ -8,31 +8,34 @@ static void test_init_skills(CuTest *tc) { struct locale *lang; - test_cleanup(); + test_setup(); lang = get_or_create_locale("de"); + init_skill(lang, SK_ALCHEMY, "Alchemie"); CuAssertIntEquals(tc, SK_ALCHEMY, get_skill("alchemie", lang)); - test_cleanup(); + test_teardown(); } static void test_init_skill(CuTest *tc) { struct locale *lang; - test_cleanup(); + test_setup(); lang = get_or_create_locale("de"); + init_skill(lang, SK_ALCHEMY, "Alchemie"); CuAssertIntEquals(tc, SK_ALCHEMY, get_skill("alchemie", lang)); CuAssertIntEquals(tc, NOSKILL, get_skill("east", lang)); - test_cleanup(); + test_teardown(); } static void test_get_skill(CuTest *tc) { - test_cleanup(); + test_setup(); CuAssertIntEquals(tc, SK_ALCHEMY, findskill("alchemy")); CuAssertIntEquals(tc, SK_MAGIC, findskill("magic")); CuAssertIntEquals(tc, SK_CROSSBOW, findskill("crossbow")); CuAssertIntEquals(tc, NOSKILL, findskill("")); CuAssertIntEquals(tc, NOSKILL, findskill("potato")); + test_teardown(); } CuSuite *get_skill_suite(void) diff --git a/src/spells.c b/src/spells.c index c9e914904..8334d19c0 100644 --- a/src/spells.c +++ b/src/spells.c @@ -11,22 +11,36 @@ * This program may not be used, modified or distributed without * prior permission by the authors of Eressea. */ - +#ifdef _MSC_VER #include -#include +#endif + +#include "spells.h" #include "guard.h" +#include "reports.h" #include "spy.h" #include "vortex.h" #include "laws.h" -#include "spells.h" #include "direction.h" #include "randenc.h" #include "monsters.h" #include "teleport.h" +#include "xmlreader.h" -#include + /* triggers includes */ +#include +#include +#include +#include +#include +#include + /* attributes includes */ +#include +#include +#include +#include #include #include #include @@ -37,6 +51,7 @@ /* kernel includes */ #include +#include #include #include #include @@ -53,18 +68,15 @@ #include #include #include -#include - -#include /* util includes */ #include #include #include -#include #include #include #include +#include #include #include #include @@ -73,7 +85,7 @@ #include #include #include -#include +#include #include #include #include @@ -89,17 +101,6 @@ #include #include -/* triggers includes */ -#include -#include -#include -#include -#include -#include - -/* attributes includes */ -#include -#include /* ----------------------------------------------------------------------- */ #if defined(_MSC_VER) && _MSC_VER >= 1900 @@ -150,7 +151,7 @@ static void magicanalyse_region(region * r, unit * mage, double force) * mehr als 100% probability und damit immer ein Erfolg. */ probability = curse_chance(c, force); mon = c->duration + (rng_int() % 10) - 5; - mon = MAX(1, mon); + if (mon < 1) mon = 1; found = true; if (chance(probability)) { /* Analyse geglueckt */ @@ -191,7 +192,7 @@ static void magicanalyse_unit(unit * u, unit * mage, double force) * mehr als 100% probability und damit immer ein Erfolg. */ probability = curse_chance(c, force); mon = c->duration + (rng_int() % 10) - 5; - mon = MAX(1, mon); + if (mon < 1) mon = 1; if (chance(probability)) { /* Analyse geglueckt */ if (c_flags(c) & CURSE_NOAGE) { @@ -232,7 +233,7 @@ static void magicanalyse_building(building * b, unit * mage, double force) * mehr als 100% probability und damit immer ein Erfolg. */ probability = curse_chance(c, force); mon = c->duration + (rng_int() % 10) - 5; - mon = MAX(1, mon); + if (mon < 1) mon = 1; if (chance(probability)) { /* Analyse geglueckt */ if (c_flags(c) & CURSE_NOAGE) { @@ -273,7 +274,7 @@ static void magicanalyse_ship(ship * sh, unit * mage, double force) * mehr als 100% probability und damit immer ein Erfolg. */ probability = curse_chance(c, force); mon = c->duration + (rng_int() % 10) - 5; - mon = MAX(1, mon); + if (mon < 1) mon = 1; if (chance(probability)) { /* Analyse geglueckt */ if (c_flags(c) & CURSE_NOAGE) { @@ -536,12 +537,9 @@ static int sp_summon_familiar(castorder * co) unit *mage = co->magician.u; int cast_level = co->level; const race *rc; - int sk; - int dh, dh1; - size_t bytes; + int dh; message *msg; - char zText[2048], *bufp = zText; - size_t size = sizeof(zText) - 1; + char zText[2048]; if (get_familiar(mage) != NULL) { cmistake(mage, co->order, 199, MSG_MAGIC); @@ -581,40 +579,7 @@ static int sp_summon_familiar(castorder * co) msg_release(msg); make_familiar(mage, r, rc, zText); - dh = 0; - dh1 = 0; - for (sk = 0; sk < MAXSKILLS; ++sk) { - if (skill_enabled(sk) && rc->bonus[sk] > -5) - dh++; - } - - for (sk = 0; sk < MAXSKILLS; sk++) { - if (skill_enabled(sk) && rc->bonus[sk] > -5) { - dh--; - if (dh1 == 0) { - dh1 = 1; - } - else { - if (dh == 0) { - bytes = - strlcpy(bufp, (const char *)LOC(mage->faction->locale, - "list_and"), size); - } - else { - bytes = strlcpy(bufp, (const char *)", ", size); - } - assert(bytes <= INT_MAX); - if (wrptr(&bufp, &size, (int)bytes) != 0) - WARN_STATIC_BUFFER(); - } - bytes = - strlcpy(bufp, (const char *)skillname((skill_t)sk, mage->faction->locale), - size); - assert(bytes <= INT_MAX); - if (wrptr(&bufp, &size, (int)bytes) != 0) - WARN_STATIC_BUFFER(); - } - } + report_race_skills(rc, zText, sizeof(zText), mage->faction->locale); ADDMSG(&mage->faction->msgs, msg_message("familiar_describe", "mage race skills", mage, rc, zText)); return cast_level; @@ -702,7 +667,8 @@ static int sp_destroy_magic(castorder * co) "unit region command", mage, mage->region, co->order)); } - return MAX(succ, 1); + if (succ < 1) succ = 1; + return succ; } /* ------------------------------------------------------------- */ @@ -771,7 +737,9 @@ static int sp_transferaura(castorder * co) return 0; } - gain = MIN(aura, scm_src->spellpoints) / multi; + gain = scm_src->spellpoints; + if (gain > aura) gain = aura; + gain = gain / multi; scm_src->spellpoints -= gain * multi; scm_dst->spellpoints += gain; @@ -902,7 +870,7 @@ static int sp_summonent(castorder * co) double power = co->force; unit *u; attrib *a; - int ents; + int ents, p2; if (rtrees(r, 2) == 0) { cmistake(mage, co->order, 204, MSG_EVENT); @@ -910,7 +878,9 @@ static int sp_summonent(castorder * co) return 0; } - ents = MIN((int)(power * power), rtrees(r, 2)); + ents = rtrees(r, 2); + p2 = (int)(power * power); + if (ents > p2) ents = p2; u = create_unit(r, mage->faction, ents, get_race(RC_TREEMAN), 0, NULL, mage); @@ -1280,10 +1250,8 @@ static int sp_rosthauch(castorder * co) add_ironweapon(it_find("axe"), it_find("rustyaxe"), 1.0); add_ironweapon(it_find("greatsword"), it_find("rustygreatsword"), 1.0); add_ironweapon(it_find("halberd"), it_find("rustyhalberd"), 0.5f); -#ifndef NO_RUSTY_ARMOR add_ironweapon(it_find("shield"), it_find("rustyshield"), 0.5f); add_ironweapon(it_find("chainmail"), it_find("rustychainmail"), 0.2f); -#endif } if (force > 0) { @@ -1303,7 +1271,8 @@ static int sp_rosthauch(castorder * co) for (; iweapon != NULL; iweapon = iweapon->next) { item **ip = i_find(&u->items, iweapon->type); if (*ip) { - float chance = (float)MIN((*ip)->number, force); + double chance = (*ip)->number; + if (chance > force) chance = force; if (iweapon->chance < 1.0) { chance *= iweapon->chance; } @@ -1342,7 +1311,7 @@ static int sp_rosthauch(castorder * co) * unguenstigsten Fall kann pro Stufe nur eine Waffe verzaubert werden, * darum wird hier nur fuer alle Faelle in denen noch weniger Waffen * betroffen wurden ein Kostennachlass gegeben */ - return MIN(success, cast_level); + return (success < cast_level) ? success : cast_level; } /* ------------------------------------------------------------- */ @@ -1372,9 +1341,12 @@ static int sp_kaelteschutz(castorder * co) unit *mage = co->magician.u; int cast_level = co->level; double force = co->force; - int duration = MAX(cast_level, (int)force) + 1; - spellparameter *pa = co->par; double effect; + spellparameter *pa = co->par; + int duration = (int)force; + + if (duration < cast_level) duration = cast_level; + ++duration; force *= 10; /* 10 Personen pro Force-Punkt */ @@ -2135,8 +2107,8 @@ static int sp_drought(castorder * co) */ c = get_curse(r->attribs, &ct_drought); if (c) { - c->vigour = MAX(c->vigour, power); - c->duration = MAX(c->duration, (int)power); + c->vigour = fmax(c->vigour, power); + if (c->duration < (int)power) c->duration = (int)power; } else { double effect = 4.0; @@ -2320,7 +2292,6 @@ static int sp_stormwinds(castorder * co) */ static int sp_earthquake(castorder * co) { - int kaputt; region *r = co_get_region(co); unit *mage = co->magician.u; int cast_level = co->level; @@ -2333,8 +2304,9 @@ static int sp_earthquake(castorder * co) if (burg->size != 0 && !is_cursed(burg->attribs, &ct_magicwalls)) { /* Magieresistenz */ if (!target_resists_magic(mage, burg, TYP_BUILDING, 0)) { - kaputt = MIN(10 * cast_level, burg->size / 4); - kaputt = MAX(kaputt, 1); + int kaputt = burg->size / 4; + if (kaputt > 10 * cast_level) kaputt = 10 * cast_level; + if (kaputt < 1) kaputt = 1; burg->size -= kaputt; if (burg->size == 0) { /* TODO: sollten die Insassen nicht Schaden nehmen? */ @@ -2358,7 +2330,6 @@ static int sp_earthquake(castorder * co) /* ------------------------------------------------------------- */ void patzer_peasantmob(const castorder * co) { - int anteil = 6, n; unit *u; attrib *a; region *r; @@ -2370,8 +2341,9 @@ void patzer_peasantmob(const castorder * co) faction *f = get_monsters(); const struct locale *lang = f->locale; message *msg; + int anteil, n; - anteil += rng_int() % 4; + anteil = 6 + rng_int() % 4; n = rpeasants(r) * anteil / 10; rsetpeasants(r, rpeasants(r) - n); assert(rpeasants(r) >= 0); @@ -2510,7 +2482,6 @@ static int sp_forest_fire(castorder * co) static int sp_fumblecurse(castorder * co) { unit *target; - int rx, sx; int duration; unit *mage = co->magician.u; int cast_level = co->level; @@ -2525,9 +2496,12 @@ static int sp_fumblecurse(castorder * co) target = pa->param[0]->data.u; - rx = rng_int() % 3; - sx = cast_level - effskill(target, SK_MAGIC, 0); - duration = MAX(sx, rx) + 1; + duration = cast_level - effskill(target, SK_MAGIC, 0); + if (duration < 2) { + int rx = rng_int() % 3; + if (duration < rx) duration = rx; + } + ++duration; effect = force / 2; c = create_curse(mage, &target->attribs, &ct_fumble, @@ -2693,8 +2667,9 @@ static int sp_firewall(castorder * co) } else { fd = (wall_data *)b->data.v; - fd->force = (int)MAX(fd->force, force / 2 + 0.5); - fd->countdown = MAX(fd->countdown, cast_level + 1); + fd->force = (int)fmax(fd->force, force / 2 + 0.5); + if (fd->countdown < cast_level + 1) + fd->countdown = cast_level + 1; } /* melden, 1x pro Partei */ @@ -2966,12 +2941,12 @@ static int sp_deathcloud(castorder * co) return co->level; } -void patzer_deathcloud(castorder * co) +static void patzer_deathcloud(const castorder * co) { unit *mage = co->magician.u; int hp = (mage->hp - 2); - change_hitpoints(mage, -rng_int() % hp); + change_hitpoints(mage, -(rng_int() % hp)); ADDMSG(&mage->faction->msgs, msg_message("magic_fumble", "unit region command", mage, mage->region, co->order)); @@ -3274,7 +3249,7 @@ static void skill_summoned(unit * u, int level) */ static int sp_summonundead(castorder * co) { - int undead; + int undead, dc; unit *u; region *r = co_get_region(co); unit *mage = co->magician.u; @@ -3288,7 +3263,9 @@ static int sp_summonundead(castorder * co) return 0; } - undead = MIN(deathcount(r), 2 + lovar(force)); + undead = 2 + lovar(force); + dc = deathcount(r); + if (undead > dc) undead = dc; if (cast_level <= 8) { race = get_race(RC_SKELETON); @@ -3336,7 +3313,7 @@ static int sp_auraleak(castorder * co) int cast_level = co->level; message *msg; - lost = MIN(0.95, cast_level * 0.05); + lost = fmin(0.95, cast_level * 0.05); for (u = r->units; u; u = u->next) { if (is_mage(u)) { @@ -3710,17 +3687,17 @@ static int sp_raisepeasantmob(castorder * co) int anteil; region *r = co_get_region(co); unit *mage = co->magician.u; - int cast_level = co->level; + int rp, cast_level = co->level; double force = co->force; int duration = (int)force + 1; faction *monsters = get_monsters(); message *msg; anteil = 6 + (rng_int() % 4); - - n = rpeasants(r) * anteil / 10; - n = MAX(0, n); - n = MIN(n, rpeasants(r)); + rp = rpeasants(r); + n = rp * anteil / 10; + if (n < 0) n = 0; + if (n > rp) n = rp; if (n <= 0) { report_failure(mage, co->order); @@ -3959,13 +3936,13 @@ static int sp_recruit(castorder * co) n = (pow(force, 1.6) * 100) / f->race->recruitcost; if (rc->recruit_multi > 0) { double multp = (double)maxp / rc->recruit_multi; - n = MIN(multp, n); - n = MAX(n, 1); + n = fmin(multp, n); + n = fmax(n, 1); rsetpeasants(r, maxp - (int)(n * rc->recruit_multi)); } else { - n = MIN(maxp, n); - n = MAX(n, 1); + n = fmin(maxp, n); + n = fmax(n, 1); rsetpeasants(r, maxp - (int)n); } @@ -4010,18 +3987,17 @@ static int sp_bigrecruit(castorder * co) n = (int)force + lovar((force * force * 1000) / (float)f->race->recruitcost); if (f->race == get_race(RC_ORC)) { - n = MIN(2 * maxp, n); - n = MAX(n, 1); + if (n > 2 * maxp) n = 2 * maxp; + if (n < 1) n = 1; rsetpeasants(r, maxp - (n + 1) / 2); } else { - n = MIN(maxp, n); - n = MAX(n, 1); + if (n > maxp) n = maxp; + if (n < 1) n = 1; rsetpeasants(r, maxp - n); } - u = - create_unit(r, f, n, f->race, 0, LOC(f->locale, + u = create_unit(r, f, n, f->race, 0, LOC(f->locale, (n == 1 ? "peasant" : "peasant_p")), mage); set_order(&u->thisorder, default_order(f->locale)); @@ -4136,9 +4112,9 @@ static int sp_seduce(castorder * co) item *itm = *itmp; int loot; if (itm->type->rtype == rsilver) { - loot = - MIN(cast_level * 1000, get_money(target) - (maintenance_cost(target))); - loot = MAX(loot, 0); + loot = get_money(target) - maintenance_cost(target); + if (loot > cast_level * 1000) loot = cast_level * 1000; + if (loot < 0) loot = 0; } else { loot = itm->number / 2; @@ -4146,7 +4122,8 @@ static int sp_seduce(castorder * co) loot += rng_int() % 2; } if (loot > 0) { - loot = MIN(loot, (int)(force * 5)); + int floot = (int)(5 * force); + if (loot > floot) loot = floot; } } if (loot > 0) { @@ -4263,7 +4240,9 @@ static int sp_headache(castorder * co) } if (smax != NULL) { /* wirkt auf maximal 10 Personen */ - unsigned int change = MIN(10, target->number) * (rng_uint() % 2 + 1) / target->number; + int change = target->number; + if (change > 10) change = 10; + change *= (rng_uint() % 2 + 1) / target->number; reduce_skill(target, smax, change); } set_order(&target->thisorder, NULL); @@ -4298,17 +4277,18 @@ static int sp_raisepeasants(castorder * co) attrib *a; region *r = co_get_region(co); unit *mage = co->magician.u; - int cast_level = co->level; + int rp = rpeasants(r), cast_level = co->level; double power = co->force; message *msg; - if (rpeasants(r) == 0) { + if (rp == 0) { ADDMSG(&mage->faction->msgs, msg_feedback(mage, co->order, "error_nopeasants", "")); return 0; } - bauern = MIN(rpeasants(r), (int)(power * 250)); - rsetpeasants(r, rpeasants(r) - bauern); + bauern = (int)(power * 250); + if (bauern > rp) bauern = rp; + rsetpeasants(r, rp - bauern); u2 = create_unit(r, mage->faction, bauern, get_race(RC_PEASANT), 0, @@ -4390,7 +4370,7 @@ int sp_puttorest(castorder * co) message *seen = msg_message("puttorest", "mage", mage); message *unseen = msg_message("puttorest", "mage", NULL); - laid_to_rest = MAX(laid_to_rest, dead); + if (laid_to_rest < dead) laid_to_rest = dead; deathcounts(r, -laid_to_rest); @@ -4527,28 +4507,6 @@ int sp_illusionary_shapeshift(castorder * co) return cast_level; } -/* ------------------------------------------------------------- */ -/* Name: Regionstraum analysieren - * Stufe: 9 - * Aura: 18 - * Kosten: SPC_FIX - * Wirkung: - * Zeigt die Verzauberungen eines Objekts an (curse->name, - * curse::info). Aus der Differenz Spruchstaerke und Curse->vigour - * ergibt sich die Chance den Spruch zu identifizieren ((force - - * c->vigour)*10 + 100 %). - */ -int sp_analyseregionsdream(castorder * co) -{ - region *r = co_get_region(co); - unit *mage = co->magician.u; - int cast_level = co->level; - - magicanalyse_region(r, mage, cast_level); - - return cast_level; -} - /* ------------------------------------------------------------- */ /* Name: Traumbilder erkennen * Stufe: 5 @@ -4592,7 +4550,7 @@ static int sp_gbdreams(castorder * co, int effect) /* wirkt erst in der Folgerunde, soll mindestens eine Runde wirken, * also duration+2 */ - duration = (int)MAX(1, power / 2); /* Stufe 1 macht sonst mist */ + duration = (int)fmax(1, power / 2); /* Stufe 1 macht sonst mist */ duration = 2 + rng_int() % duration; /* Nichts machen als ein entsprechendes Attribut in die Region legen. */ @@ -4667,7 +4625,7 @@ int sp_clonecopy(castorder * co) return 0; } - slprintf(name, sizeof(name), (const char *)LOC(mage->faction->locale, + snprintf(name, sizeof(name), (const char *)LOC(mage->faction->locale, "clone_of"), unitname(mage)); clone = create_unit(target_region, mage->faction, 1, get_race(RC_CLONE), 0, name, @@ -4764,7 +4722,8 @@ int sp_sweetdreams(castorder * co) cmistake(mage, co->order, 40, MSG_EVENT); continue; } - men = MIN(opfer, u->number); + men = u->number; + if (men > opfer) men = opfer; opfer -= men; /* Nichts machen als ein entsprechendes Attribut an die Einheit legen. */ @@ -4877,7 +4836,7 @@ int sp_itemcloak(castorder * co) spellparameter *pa = co->par; int cast_level = co->level; double power = co->force; - int duration = (int)MAX(2.0, power + 1); /* works in the report, and ageing this round would kill it if it's <=1 */ + int duration = (int)fmax(2.0, power + 1); /* works in the report, and ageing this round would kill it if it's <=1 */ /* wenn kein Ziel gefunden, Zauber abbrechen */ if (pa->param[0]->flag == TARGET_NOTFOUND) @@ -4935,7 +4894,8 @@ int sp_resist_magic_bonus(castorder * co) u = pa->param[n]->data.u; - m = MIN(u->number, victims); + m = u->number; + if (m > victims) m = victims; victims -= m; create_curse(mage, &u->attribs, &ct_magicresistance, @@ -4951,8 +4911,10 @@ int sp_resist_magic_bonus(castorder * co) msg_release(msg); } - cast_level = MIN(cast_level, (int)(cast_level * (victims + 4) / maxvictims)); - return MAX(cast_level, 1); + m = (int)(cast_level * (victims + 4) / maxvictims); + if (m > cast_level) m = cast_level; + if (m < 1) m = 1; + return m; } /** spell 'Astraler Weg'. @@ -5476,7 +5438,8 @@ int sp_fetchastral(castorder * co) return cast_level; } -#ifdef SHOWASTRAL_NOT_BORKED +#define SHOWASTRAL_IS_BORKED +#ifndef SHOWASTRAL_IS_BORKED int sp_showastral(castorder * co) { unit *u; @@ -5563,8 +5526,6 @@ int sp_showastral(castorder * co) free_regionlist(rl); return cast_level; - UNUSED_ARG(co); - return 0; } #endif @@ -5780,7 +5741,7 @@ static int sp_eternizewall(castorder * co) */ int sp_permtransfer(castorder * co) { - int aura; + int aura, i; unit *tu; unit *mage = co->magician.u; int cast_level = co->level; @@ -5807,7 +5768,8 @@ int sp_permtransfer(castorder * co) return 0; } - aura = MIN(get_spellpoints(mage) - spellcost(mage, sp), aura); + i = get_spellpoints(mage) - spellcost(mage, sp); + if (aura > i) aura = i; change_maxspellpoints(mage, -aura); change_spellpoints(mage, -aura); @@ -6116,7 +6078,8 @@ int sp_speed2(castorder * co) spellparameter *pa = co->par; maxmen = 2 * cast_level * cast_level; - dur = MAX(1, cast_level / 2); + dur = cast_level / 2; + if (dur < 1) dur = 1; for (n = 0; n < pa->length; n++) { double effect; @@ -6130,7 +6093,7 @@ int sp_speed2(castorder * co) u = pa->param[n]->data.u; - men = MIN(maxmen, u->number); + men = (maxmen <= u->number) ? maxmen : u->number; effect = 2; create_curse(mage, &u->attribs, &ct_speed, force, dur, effect, men); maxmen -= men; @@ -6141,90 +6104,8 @@ int sp_speed2(castorder * co) "unit region amount", mage, mage->region, used)); /* Effektiv benoetigten cast_level (mindestens 1) zurueckgeben */ used = (int)sqrt(used / 2); - return MAX(1, used); -} - -/* ------------------------------------------------------------- */ -/* Name: Magiefresser - * Stufe: 7 - * Kosten: SPC_LEVEL - * - * Wirkung: - * Kann eine bestimmte Verzauberung angreifen und aufloesen. Die Staerke - * des Zaubers muss staerker sein als die der Verzauberung. - * Syntax: - * ZAUBERE \"Magiefresser\" REGION - * ZAUBERE \"Magiefresser\" EINHEIT - * ZAUBERE \"Magiefresser\" GEBAEUDE - * ZAUBERE \"Magiefresser\" SCHIFF - * - * "kc?c" - * Flags: - * (FARCASTING | SPELLLEVEL | ONSHIPCAST | TESTCANSEE) - */ - /* Jeder gebrochene Zauber verbraucht c->vigour an Zauberkraft - * (force) */ -int sp_q_antimagie(castorder * co) -{ - attrib **ap; - int obj; - curse *c = NULL; - int succ; - region *r = co_get_region(co); - unit *mage = co->magician.u; - int cast_level = co->level; - double force = co->force; - spellparameter *pa = co->par; - const char *ts = NULL; - - obj = pa->param[0]->typ; - - switch (obj) { - case SPP_REGION: - ap = &r->attribs; - ts = regionname(r, mage->faction); - break; - - case SPP_TEMP: - case SPP_UNIT: - { - unit *u = pa->param[0]->data.u; - ap = &u->attribs; - ts = itoa36(u->no); - break; - } - case SPP_BUILDING: - { - building *b = pa->param[0]->data.b; - ap = &b->attribs; - ts = itoa36(b->no); - break; - } - case SPP_SHIP: - { - ship *sh = pa->param[0]->data.sh; - ap = &sh->attribs; - ts = itoa36(sh->no); - break; - } - default: - /* Das Zielobjekt wurde vergessen */ - cmistake(mage, co->order, 203, MSG_MAGIC); - return 0; - } - - succ = break_curse(ap, cast_level, force, c); - - if (succ) { - ADDMSG(&mage->faction->msgs, msg_message("destroy_magic_effect", - "unit region command succ target", mage, mage->region, co->order, succ, - ts)); - } - else { - ADDMSG(&mage->faction->msgs, msg_message("destroy_magic_noeffect", - "unit region command", mage, mage->region, co->order)); - } - return MAX(succ, 1); + if (used < 1) used = 1; + return used; } /* ------------------------------------------------------------- */ @@ -6541,7 +6422,7 @@ static spelldata spell_functions[] = { { "forestfire", sp_forest_fire, patzer_peasantmob }, { "draigdestroymagic", sp_destroy_magic, 0 }, { "unholypower", sp_unholypower, 0 }, - { "deathcloud", sp_deathcloud, patzer_peasantmob }, + { "deathcloud", sp_deathcloud, patzer_deathcloud }, { "summondragon", sp_summondragon, patzer_peasantmob }, { "summonshadowlords", sp_summonshadowlords, patzer_peasantmob }, { "chaossuction", sp_chaossuction, patzer_peasantmob }, @@ -6567,7 +6448,7 @@ static spelldata spell_functions[] = { { "mindblast", sp_mindblast_temp, 0 }, { "orkdream", sp_sweetdreams, 0 }, /* M_CERDDOR */ - { "appeasement", sp_denyattack, 0 }, + { "appeasement", sp_appeasement, 0 }, { "song_of_healing", sp_healing, 0 }, { "generous", sp_generous, 0 }, { "song_of_fear", sp_song_of_fear, 0 }, @@ -6600,7 +6481,7 @@ static spelldata spell_functions[] = { { "analyze_magic", sp_analysemagic, 0 }, { "concealing_aura", sp_itemcloak, 0 }, { "tybiedfumbleshield", sp_fumbleshield, 0 }, -#ifdef SHOWASTRAL_NOT_BORKED +#ifndef SHOWASTRAL_IS_BORKED { "show_astral", sp_showastral, 0 }, #endif { "resist_magic", sp_resist_magic_bonus, 0 }, diff --git a/src/spells.test.c b/src/spells.test.c index 638d1e858..e151e7680 100644 --- a/src/spells.test.c +++ b/src/spells.test.c @@ -12,8 +12,9 @@ #include #include #include -#include #include +#include +#include #include #include @@ -26,6 +27,10 @@ #include #include +static void setup_spells(void) { + test_inject_messagetypes(); +} + static void test_good_dreams(CuTest *tc) { struct region *r; struct faction *f1, *f2; @@ -35,10 +40,11 @@ static void test_good_dreams(CuTest *tc) { curse *curse; test_setup(); + setup_spells(); test_create_world(); r = findregion(0, 0); - f1 = test_create_faction(0); - f2 = test_create_faction(0); + f1 = test_create_faction(NULL); + f2 = test_create_faction(NULL); u1 = test_create_unit(f1, r); u2 = test_create_unit(f2, r); @@ -54,7 +60,7 @@ static void test_good_dreams(CuTest *tc) { CuAssertIntEquals_Msg(tc, "good dreams give +1 to allies", 1, get_modifier(u1, SK_MELEE, 11, r, false)); CuAssertIntEquals_Msg(tc, "good dreams have no effect on non-allies", 0, get_modifier(u2, SK_MELEE, 11, r, false)); free_castorder(&co); - test_cleanup(); + test_teardown(); } static void test_dreams(CuTest *tc) { @@ -63,11 +69,11 @@ static void test_dreams(CuTest *tc) { unit *u1, *u2; castorder co; - test_cleanup(); - test_create_world(); - r = findregion(0, 0); - f1 = test_create_faction(0); - f2 = test_create_faction(0); + test_setup(); + setup_spells(); + r = test_create_region(0, 0, NULL); + f1 = test_create_faction(NULL); + f2 = test_create_faction(NULL); u1 = test_create_unit(f1, r); u2 = test_create_unit(f2, r); @@ -80,7 +86,7 @@ static void test_dreams(CuTest *tc) { CuAssertIntEquals_Msg(tc, "bad dreams in same region as good dreams", -1, get_modifier(u2, SK_MELEE, 11, r, false)); free_castorder(&co); - test_cleanup(); + test_teardown(); } static void test_bad_dreams(CuTest *tc) { @@ -92,10 +98,11 @@ static void test_bad_dreams(CuTest *tc) { curse *curse; test_setup(); + setup_spells(); test_create_world(); r = findregion(0, 0); - f1 = test_create_faction(0); - f2 = test_create_faction(0); + f1 = test_create_faction(NULL); + f2 = test_create_faction(NULL); u1 = test_create_unit(f1, r); u2 = test_create_unit(f2, r); @@ -112,7 +119,7 @@ static void test_bad_dreams(CuTest *tc) { CuAssertIntEquals_Msg(tc, "bad dreams give -1 to non-allies", -1, get_modifier(u2, SK_MELEE, 11, r, false)); free_castorder(&co); - test_cleanup(); + test_teardown(); } static void test_view_reality(CuTest *tc) { @@ -122,10 +129,13 @@ static void test_view_reality(CuTest *tc) { castorder co; test_setup(); + setup_spells(); + mt_register(mt_new_va("spell_astral_only", "unit:unit", "region:region", "command:order", NULL)); + mt_register(mt_new_va("viewreality_effect", "unit:unit", NULL)); r = test_create_region(0, 0, NULL); ra = test_create_region(real2tp(r->x), real2tp(r->y), NULL); ra->_plane = get_astralplane(); - f = test_create_faction(0); + f = test_create_faction(NULL); u = test_create_unit(f, r); test_create_castorder(&co, u, 10, 10., 0, NULL); @@ -146,15 +156,16 @@ static void test_view_reality(CuTest *tc) { CuAssertPtrNotNull(tc, test_find_messagetype(ra->individual_messages->msgs, "viewreality_effect")); free_castorder(&co); - test_cleanup(); + test_teardown(); } static void test_watch_region(CuTest *tc) { region *r; faction *f; test_setup(); - r = test_create_region(0, 0, 0); - f = test_create_faction(0); + setup_spells(); + r = test_create_region(0, 0, NULL); + f = test_create_faction(NULL); CuAssertIntEquals(tc, -1, get_observer(r, f)); set_observer(r, f, 0, 2); CuAssertIntEquals(tc, 0, get_observer(r, f)); @@ -162,7 +173,7 @@ static void test_watch_region(CuTest *tc) { CuAssertIntEquals(tc, 10, get_observer(r, f)); CuAssertIntEquals(tc, RF_OBSERVER, fval(r, RF_OBSERVER)); CuAssertPtrNotNull(tc, r->attribs); - test_cleanup(); + test_teardown(); } CuSuite *get_spells_suite(void) diff --git a/src/spells/borders.c b/src/spells/borders.c index d19470230..9ded973c8 100644 --- a/src/spells/borders.c +++ b/src/spells/borders.c @@ -1,5 +1,6 @@ +#ifdef _MSC_VER #include - +#endif #include "borders.h" #include "vortex.h" @@ -15,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -119,7 +121,7 @@ struct region *from, struct region *to, bool routing) wall_data *fd = (wall_data *)b->data.v; if (!routing && fd->active) { int hp = dice(3, fd->force) * u->number; - hp = MIN(u->hp, hp); + if (u->hp < hp) hp = u->hp; u->hp -= hp; if (u->hp) { ADDMSG(&u->faction->msgs, msg_message("firewall_damage", diff --git a/src/spells/buildingcurse.c b/src/spells/buildingcurse.c index 06c62e1c4..e1eff8988 100644 --- a/src/spells/buildingcurse.c +++ b/src/spells/buildingcurse.c @@ -26,6 +26,7 @@ #include #include #include +#include /* libc includes */ #include diff --git a/src/spells/combatspells.c b/src/spells/combatspells.c index 8eb240cf7..ce737f570 100644 --- a/src/spells/combatspells.c +++ b/src/spells/combatspells.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -622,7 +623,6 @@ int sp_dragonodem(struct castorder * co) troop dt; troop at; int force, enemies; - int killed = 0; const char *damage; /* 11-26 HP */ @@ -641,6 +641,7 @@ int sp_dragonodem(struct castorder * co) } else { struct message *m; + int killed = 0; at.fighter = fi; at.index = 0; @@ -717,53 +718,6 @@ int sp_immolation(struct castorder * co) return level; } -int sp_drainodem(fighter * fi, int level, double power, spell * sp) -{ - battle *b = fi->side->battle; - troop dt; - troop at; - int force, enemies; - int drained = 0; - int killed = 0; - const char *damage; - message *m; - - /* 11-26 HP */ - damage = spell_damage(4); - /* Jungdrache 3->54, Drache 6->216, Wyrm 12->864 Treffer */ - force = lovar(get_force(power, 6)); - - enemies = count_enemies(b, fi, FIGHT_ROW, BEHIND_ROW - 1, SELECT_ADVANCE); - - if (!enemies) { - m = msg_message("spell_out_of_range", "mage spell", fi->unit, sp); - message_all(b, m); - msg_release(m); - return 0; - } - - at.fighter = fi; - at.index = 0; - - while (force && drained < enemies) { - dt = select_enemy(fi, FIGHT_ROW, BEHIND_ROW - 1, SELECT_ADVANCE); - assert(dt.fighter); - if (hits(at, dt, NULL)) { - drain_exp(dt.fighter->unit, 90); - ++drained; - killed += terminate(dt, at, AT_COMBATSPELL, damage, false); - } - --force; - } - - m = - msg_message("cast_drainlife_effect", "mage spell amount", fi->unit, sp, - drained); - message_all(b, m); - msg_release(m); - return level; -} - /* ------------------------------------------------------------- */ /* PRECOMBAT */ @@ -1309,7 +1263,7 @@ int sp_reeling_arrows(struct castorder * co) /* Magier weicht dem Kampf aus. Wenn er sich bewegen kann, zieht er in * eine Nachbarregion, wobei ein NACH ber�cksichtigt wird. Ansonsten * bleibt er stehen und nimmt nicht weiter am Kampf teil. */ -int sp_denyattack(struct castorder * co) +int sp_appeasement(struct castorder * co) { fighter * fi = co->magician.fig; int level = co->level; @@ -1326,7 +1280,7 @@ int sp_denyattack(struct castorder * co) } /* und bewachen nicht */ setguard(mage, false); - /* irgendwie den langen befehl sperren */ + setstatus(mage, ST_FLEE); /* wir tun so, als w�re die Person geflohen */ fi->flags |= FIG_NOLOOT; diff --git a/src/spells/combatspells.h b/src/spells/combatspells.h index 78da949e8..edd041704 100644 --- a/src/spells/combatspells.h +++ b/src/spells/combatspells.h @@ -30,7 +30,7 @@ extern "C" { int sp_berserk(struct castorder * co); int sp_tiredsoldiers(struct castorder * co); int sp_reeling_arrows(struct castorder * co); - int sp_denyattack(struct castorder * co); + int sp_appeasement(struct castorder * co); int sp_sleep(struct castorder * co); int sp_windshield(struct castorder * co); int sp_strong_wall(struct castorder * co); diff --git a/src/spells/flyingship.test.c b/src/spells/flyingship.test.c index 98e524926..3459adcd3 100644 --- a/src/spells/flyingship.test.c +++ b/src/spells/flyingship.test.c @@ -7,6 +7,8 @@ #include #include +#include + #include #include @@ -26,13 +28,14 @@ static void test_flyingship(CuTest * tc) ship_type *shipType1, *shipType2; ship *sh1, *sh2; - test_cleanup(); + test_setup(); + mt_register(mt_new_va("flying_ship_result", "mage:unit", "ship:ship", NULL)); par.param = &par_data_ptr; par_data.typ = SPP_SHIP; par_data.flag = 0; - r = test_create_region(0, 0, 0); + r = test_create_region(0, 0, NULL); f = test_create_faction(test_create_race("human")); u = test_create_unit(f, r); @@ -61,7 +64,7 @@ static void test_flyingship(CuTest * tc) CuAssertTrue(tc, !flying_ship(sh2)); co.par = 0; free_castorder(&co); - test_cleanup(); + test_teardown(); } CuSuite *get_flyingship_suite(void) diff --git a/src/spells/magicresistance.c b/src/spells/magicresistance.c index 6f2ec49ec..f5cbb55dd 100644 --- a/src/spells/magicresistance.c +++ b/src/spells/magicresistance.c @@ -10,14 +10,14 @@ static struct message *cinfo_magicresistance(const void *obj, objtype_t typ, con if (typ == TYP_UNIT) { if (self != 0) { const struct unit *u = (const struct unit *)obj; - return msg_message(mkname("curseinfo", "magicresistance_unit"), "unit id", u, + return msg_message("magicresistance_unit", "unit id", u, c->no); } return NULL; } if (typ == TYP_BUILDING) { const struct building *b = (const struct building *)obj; - return msg_message(mkname("curseinfo", "magicresistance_building"), "id building", c->no, b); + return msg_message("magicresistance_building", "id building", c->no, b); } return 0; } diff --git a/src/spells/magicresistance.test.c b/src/spells/magicresistance.test.c index 7576911af..ccce0216c 100644 --- a/src/spells/magicresistance.test.c +++ b/src/spells/magicresistance.test.c @@ -29,6 +29,7 @@ static void test_magicresistance_unit(CuTest *tc) { curse *c; test_setup(); + mt_register(mt_new_va("magicresistance_unit", "unit:unit", "id:int", NULL)); r = test_create_plain(0, 0); f1 = test_create_faction(NULL); u1 = test_create_unit(f1, r); @@ -41,10 +42,10 @@ static void test_magicresistance_unit(CuTest *tc) { CuAssertPtrEquals(tc, (void *)&at_curse, (void *)u2->attribs->type); msg = c->type->curseinfo(u2, TYP_UNIT, c, 1); CuAssertPtrNotNull(tc, msg); - CuAssertStrEquals(tc, "curseinfo::magicresistance_unit", test_get_messagetype(msg)); + CuAssertStrEquals(tc, "magicresistance_unit", test_get_messagetype(msg)); msg_release(msg); - test_cleanup(); + test_teardown(); } static void test_magicresistance_building(CuTest *tc) { @@ -56,6 +57,7 @@ static void test_magicresistance_building(CuTest *tc) { curse *c; test_setup(); + mt_register(mt_new_va("magicresistance_building", "building:building", "id:int", NULL)); r = test_create_plain(0, 0); f1 = test_create_faction(NULL); u1 = test_create_unit(f1, r); @@ -67,9 +69,9 @@ static void test_magicresistance_building(CuTest *tc) { CuAssertPtrEquals(tc, (void *)&at_curse, (void *)b1->attribs->type); msg = c->type->curseinfo(b1, TYP_BUILDING, c, 1); CuAssertPtrNotNull(tc, msg); - CuAssertStrEquals(tc, "curseinfo::magicresistance_building", test_get_messagetype(msg)); + CuAssertStrEquals(tc, "magicresistance_building", test_get_messagetype(msg)); msg_release(msg); - test_cleanup(); + test_teardown(); } CuSuite *get_magicresistance_suite(void) diff --git a/src/spells/regioncurse.c b/src/spells/regioncurse.c index 8ac3eea8c..7622b536f 100644 --- a/src/spells/regioncurse.c +++ b/src/spells/regioncurse.c @@ -25,6 +25,7 @@ /* util includes */ #include +#include #include #include #include diff --git a/src/spells/shipcurse.c b/src/spells/shipcurse.c index 180c84eea..4d62d1968 100644 --- a/src/spells/shipcurse.c +++ b/src/spells/shipcurse.c @@ -26,6 +26,7 @@ #include #include #include +#include #include diff --git a/src/spells/unitcurse.c b/src/spells/unitcurse.c index 4f8d69f64..9289bb3c6 100644 --- a/src/spells/unitcurse.c +++ b/src/spells/unitcurse.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -344,9 +345,16 @@ const struct curse_type ct_skillmod = { NULL, read_skill, write_skill }; +const struct curse_type ct_fleechance = { + "fleechance", + CURSETYP_NORM, 0, (M_DURATION | M_VIGOUR), + NULL, NULL, NULL, NULL, NULL +}; + /* ------------------------------------------------------------- */ void register_unitcurse(void) { + ct_register(&ct_fleechance); ct_register(&ct_auraboost); ct_register(&ct_magicboost); ct_register(&ct_slavery); diff --git a/src/spells/unitcurse.h b/src/spells/unitcurse.h index 681fa32de..0da3ff8ff 100644 --- a/src/spells/unitcurse.h +++ b/src/spells/unitcurse.h @@ -23,6 +23,7 @@ extern "C" { struct curse_type; struct message; + extern const struct curse_type ct_fleechance; extern const struct curse_type ct_slavery; extern const struct curse_type ct_calmmonster; extern const struct curse_type ct_speed; diff --git a/src/spy.c b/src/spy.c index 210be63e4..8d9d4fe8c 100644 --- a/src/spy.c +++ b/src/spy.c @@ -16,7 +16,9 @@ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. **/ +#ifdef _MSC_VER #include +#endif #include "spy.h" #include "guard.h" #include "laws.h" @@ -44,14 +46,15 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* util includes */ #include #include -#include #include #include #include +#include /* libc includes */ #include #include +#include #include #include #include @@ -98,12 +101,12 @@ void spy_message(int spy, const unit * u, const unit * target) first = 0; } else { - strlcat(buf, ", ", sizeof(buf)); + str_strlcat(buf, ", ", sizeof(buf)); } - strlcat(buf, (const char *)skillname((skill_t)sv->id, u->faction->locale), + str_strlcat(buf, (const char *)skillname((skill_t)sv->id, u->faction->locale), sizeof(buf)); - strlcat(buf, " ", sizeof(buf)); - strlcat(buf, itoa10(eff_skill(target, sv, target->region)), + str_strlcat(buf, " ", sizeof(buf)); + str_strlcat(buf, itoa10(eff_skill(target, sv, target->region)), sizeof(buf)); } } @@ -126,7 +129,7 @@ int spy_cmd(unit * u, struct order *ord) double spychance, observechance; region *r = u->region; - init_order(ord); + init_order_depr(ord); getunit(r, u->faction, &target); if (!target) { @@ -146,7 +149,7 @@ int spy_cmd(unit * u, struct order *ord) * Fuer jeden Talentpunkt, den das Spionagetalent das Tarnungstalent * des Opfers uebersteigt, erhoeht sich dieses um 5%*/ spy = effskill(u, SK_SPY, 0) - effskill(target, SK_STEALTH, r); - spychance = 0.1 + MAX(spy * 0.05, 0.0); + spychance = 0.1 + fmax(spy * 0.05, 0.0); if (chance(spychance)) { produceexp(u, SK_SPY, u->number); @@ -162,7 +165,7 @@ int spy_cmd(unit * u, struct order *ord) - (effskill(u, SK_STEALTH, 0) + effskill(u, SK_SPY, 0) / 2); if (invisible(u, target) >= u->number) { - observe = MIN(observe, 0); + if (observe > 0) observe = 0; } /* Anschliessend wird - unabhaengig vom Erfolg - gewuerfelt, ob der @@ -219,7 +222,7 @@ int setstealth_cmd(unit * u, struct order *ord) const char *s; int level; - init_order(ord); + init_order_depr(ord); s = gettoken(token, sizeof(token)); /* Tarne ohne Parameter: Setzt maximale Tarnung */ @@ -344,7 +347,7 @@ static int top_skill(region * r, faction * f, ship * sh, skill_t sk) for (u = r->units; u; u = u->next) { if (u->ship == sh && u->faction == f) { int s = effskill(u, sk, 0); - value = MAX(s, value); + if (value < s) value = s; } } return value; @@ -425,9 +428,8 @@ static void sink_ship(region * r, ship * sh, unit * saboteur) } } for (ui = &r->units; *ui;) { - unit *u = *ui; - /* inform this faction about the sinking ship: */ + u = *ui; if (!(u->faction->flags & FFL_SELECT)) { fset(u->faction, FFL_SELECT); if (sink_msg == NULL) { @@ -494,10 +496,10 @@ int sabotage_cmd(unit * u, struct order *ord) assert(u); assert(ord); - init_order(ord); + init_order_depr(ord); s = getstrtoken(); - p = findparam(s, u->faction->locale); + init_order_depr(NULL); switch (p) { case P_SHIP: diff --git a/src/spy.test.c b/src/spy.test.c index 11c8c1ff1..79108f03b 100644 --- a/src/spy.test.c +++ b/src/spy.test.c @@ -33,28 +33,45 @@ typedef struct { } spy_fixture; static void setup_spy(spy_fixture *fix) { - test_setup(); - fix->r = test_create_region(0, 0, NULL); - fix->spy = test_create_unit(test_create_faction(NULL), fix->r); - fix->victim = test_create_unit(test_create_faction(NULL), fix->r); + mt_register(mt_new_va("spyreport", "spy:unit", "target:unit", "status:int", NULL)); + mt_register(mt_new_va("spyreport_mage", "spy:unit", "target:unit", "type:int", NULL)); + mt_register(mt_new_va("spyreport_faction", "spy:unit", "target:unit", "faction:faction", NULL)); + mt_register(mt_new_va("spyreport_skills", "spy:unit", "target:unit", "skills:string", NULL)); + mt_register(mt_new_va("spyreport_items", "spy:unit", "target:unit", "items:items", NULL)); + mt_register(mt_new_va("destroy_ship_0", "unit:unit", "ship:ship", NULL)); + mt_register(mt_new_va("destroy_ship_1", "unit:unit", "ship:ship", NULL)); + mt_register(mt_new_va("destroy_ship_2", "unit:unit", "ship:ship", NULL)); + mt_register(mt_new_va("destroy_ship_3", "ship:ship", NULL)); + mt_register(mt_new_va("destroy_ship_4", "ship:ship", NULL)); + mt_register(mt_new_va("sink_msg", "ship:ship", "region:region", NULL)); + mt_register(mt_new_va("sink_lost_msg", "unit:unit", "region:region", "dead:int", NULL)); + mt_register(mt_new_va("sink_saved_msg", "unit:unit", "region:region", NULL)); + + if (fix) { + fix->r = test_create_region(0, 0, NULL); + fix->spy = test_create_unit(test_create_faction(NULL), fix->r); + fix->victim = test_create_unit(test_create_faction(NULL), fix->r); + } } static void test_simple_spy_message(CuTest *tc) { spy_fixture fix; + test_setup(); setup_spy(&fix); spy_message(0, fix.spy, fix.victim); CuAssertPtrNotNull(tc, test_find_messagetype(fix.spy->faction->msgs, "spyreport")); - test_cleanup(); + test_teardown(); } static void test_all_spy_message(CuTest *tc) { spy_fixture fix; item_type *itype; + test_setup(); setup_spy(&fix); enable_skill(SK_MAGIC, true); @@ -64,7 +81,7 @@ static void test_all_spy_message(CuTest *tc) { set_factionstealth(fix.victim, fix.spy->faction); itype = it_get_or_create(rt_get_or_create("sword")); - new_weapontype(itype, 0, frac_zero, NULL, 0, 0, 0, SK_MELEE, 2); + new_weapontype(itype, 0, frac_zero, NULL, 0, 0, 0, SK_MELEE); i_change(&fix.victim->items, itype, 1); spy_message(99, fix.spy, fix.victim); @@ -75,7 +92,7 @@ static void test_all_spy_message(CuTest *tc) { CuAssertPtrNotNull(tc, test_find_messagetype(fix.spy->faction->msgs, "spyreport_faction")); CuAssertPtrNotNull(tc, test_find_messagetype(fix.spy->faction->msgs, "spyreport_items")); - test_cleanup(); + test_teardown(); } static void test_sabotage_self(CuTest *tc) { @@ -84,7 +101,8 @@ static void test_sabotage_self(CuTest *tc) { order *ord; test_setup(); - r = test_create_region(0, 0, 0); + setup_spy(NULL); + r = test_create_region(0, 0, NULL); assert(r); u = test_create_unit(test_create_faction(NULL), r); assert(u && u->faction && u->region == r); @@ -94,8 +112,9 @@ static void test_sabotage_self(CuTest *tc) { assert(ord); CuAssertIntEquals(tc, 0, sabotage_cmd(u, ord)); CuAssertPtrEquals(tc, 0, r->ships); + CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "sink_msg")); free_order(ord); - test_cleanup(); + test_teardown(); } @@ -106,7 +125,9 @@ static void test_sabotage_other_fail(CuTest *tc) { message *msg; test_setup(); - r = test_create_region(0, 0, 0); + setup_spy(NULL); + + r = test_create_region(0, 0, NULL); assert(r); u = test_create_unit(test_create_faction(NULL), r); u2 = test_create_unit(test_create_faction(NULL), r); @@ -125,7 +146,7 @@ static void test_sabotage_other_fail(CuTest *tc) { CuAssertStrEquals(tc, "destroy_ship_3", test_get_messagetype(msg)); CuAssertPtrNotNull(tc, r->ships); free_order(ord); - test_cleanup(); + test_teardown(); } static void test_setstealth_cmd(CuTest *tc) { @@ -133,7 +154,7 @@ static void test_setstealth_cmd(CuTest *tc) { const struct locale *lang; test_setup(); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); lang = u->faction->locale; u->flags = UFL_ANON_FACTION | UFL_SIEGE; u->thisorder = create_order(K_SETSTEALTH, lang, "%s %s", @@ -146,7 +167,7 @@ static void test_setstealth_cmd(CuTest *tc) { LOC(lang, parameters[P_FACTION])); setstealth_cmd(u, u->thisorder); CuAssertIntEquals(tc, UFL_SIEGE | UFL_ANON_FACTION, u->flags); - test_cleanup(); + test_teardown(); } static void test_setstealth_demon(CuTest *tc) { @@ -157,13 +178,13 @@ static void test_setstealth_demon(CuTest *tc) { test_setup(); lang = test_create_locale(); rc = test_create_race("demon"); - u = test_create_unit(test_create_faction(rc), test_create_region(0, 0, 0)); + u = test_create_unit(test_create_faction(rc), test_create_region(0, 0, NULL)); rc = test_create_race("dwarf"); init_races(lang); u->thisorder = create_order(K_SETSTEALTH, lang, racename(lang, u, rc)); setstealth_cmd(u, u->thisorder); CuAssertPtrEquals(tc, (void *)rc, (void *)u->irace); - test_cleanup(); + test_teardown(); } static void test_setstealth_demon_bad(CuTest *tc) { @@ -174,13 +195,13 @@ static void test_setstealth_demon_bad(CuTest *tc) { test_setup(); lang = test_create_locale(); rc = test_create_race("demon"); - u = test_create_unit(test_create_faction(rc), test_create_region(0, 0, 0)); + u = test_create_unit(test_create_faction(rc), test_create_region(0, 0, NULL)); rc = test_create_race("smurf"); init_races(lang); u->thisorder = create_order(K_SETSTEALTH, lang, racename(lang, u, rc)); setstealth_cmd(u, u->thisorder); CuAssertPtrEquals(tc, NULL, (void *)u->irace); - test_cleanup(); + test_teardown(); } static void test_sabotage_other_success(CuTest *tc) { @@ -189,7 +210,8 @@ static void test_sabotage_other_success(CuTest *tc) { order *ord; test_setup(); - r = test_create_region(0, 0, 0); + setup_spy(NULL); + r = test_create_region(0, 0, NULL); assert(r); u = test_create_unit(test_create_faction(NULL), r); u2 = test_create_unit(test_create_faction(NULL), r); @@ -205,7 +227,7 @@ static void test_sabotage_other_success(CuTest *tc) { CuAssertIntEquals(tc, 0, sabotage_cmd(u2, ord)); CuAssertPtrEquals(tc, 0, r->ships); free_order(ord); - test_cleanup(); + test_teardown(); } CuSuite *get_spy_suite(void) diff --git a/src/sqlite.c b/src/sqlite.c deleted file mode 100644 index edb5bfc62..000000000 --- a/src/sqlite.c +++ /dev/null @@ -1,221 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -faction *get_faction_by_id(int uid) -{ - faction *f; - for (f = factions; f; f = f->next) { - if (f->subscription == uid) { - return f; - } - } - return NULL; -} - -/* -typedef struct stmt_cache { -sqlite3 *db; -sqlite3_stmt *stmt; -const char *sql; -int inuse; -} stmt_cache; - -#define MAX_STMT_CACHE 64 -static stmt_cache cache[MAX_STMT_CACHE]; -static int cache_insert; - -static sqlite3_stmt *stmt_cache_get(sqlite3 * db, const char *sql) -{ -int i; -sqlite3_stmt *stmt; - -for (i = 0; i != MAX_STMT_CACHE && cache[i].db; ++i) { -if (cache[i].sql == sql && cache[i].db == db) { -cache[i].inuse = 1; -stmt = cache[i].stmt; -sqlite3_reset(stmt); -sqlite3_clear_bindings(stmt); -return stmt; -} -} -if (i == MAX_STMT_CACHE) { -while (cache[cache_insert].inuse) { -cache[cache_insert].inuse = 0; -cache_insert = (cache_insert + 1) & (MAX_STMT_CACHE - 1); -} -i = cache_insert; -stmt = cache[i].stmt; -sqlite3_finalize(stmt); -} -cache[i].inuse = 1; -cache[i].db = db; -cache[i].sql = sql; -sqlite3_prepare_v2(db, sql, -1, &cache[i].stmt, NULL); -return cache[i].stmt; -} -*/ -typedef struct db_faction { - int uid; - int no; - char *email; - char *name; -} db_faction; - -static struct selist * -read_factions(sqlite3 * db, int game_id) { - int res; - selist *result = 0; - const char * sql = - "SELECT f.id, fd.code, fd.name, fd.email FROM faction f" - " LEFT OUTER JOIN faction_data fd" - " WHERE f.id=fd.faction_id AND f.game_id=? AND" - " fd.turn=(SELECT MAX(turn) FROM faction_data fx WHERE fx.faction_id=f.id)" - " ORDER BY f.id"; - sqlite3_stmt *stmt = 0; - sqlite3_prepare_v2(db, sql, -1, &stmt, 0); - sqlite3_bind_int(stmt, 1, game_id); - - res = sqlite3_step(stmt); - while (res == SQLITE_ROW) { - const char * text; - db_faction * dbf = (db_faction*)calloc(1, sizeof(db_faction)); - dbf->uid = (int)sqlite3_column_int64(stmt, 0); - text = (const char *)sqlite3_column_text(stmt, 1); - if (text) dbf->no = atoi36(text); - text = (const char *)sqlite3_column_text(stmt, 2); - if (text) dbf->name = strdup(text); - text = (const char *)sqlite3_column_text(stmt, 3); - if (text) dbf->email = strdup(text); - selist_push(&result, dbf); - res = sqlite3_step(stmt); - } - sqlite3_finalize(stmt); - return result; -} - -static int insert_faction(sqlite3 *db, int game_id, faction *f) { - const char *sql = "INSERT INTO faction (game_id, race) VALUES (?, ?)"; - sqlite3_stmt *stmt = 0; - sqlite3_prepare_v2(db, sql, -1, &stmt, 0); - sqlite3_bind_int(stmt, 1, game_id); - sqlite3_bind_text(stmt, 2, f->race->_name, -1, SQLITE_STATIC); - sqlite3_step(stmt); - sqlite3_finalize(stmt); - return (int)sqlite3_last_insert_rowid(db); -} - -static void update_faction(sqlite3 *db, const faction *f) { - char code[5]; - const char *sql = - "INSERT INTO faction_data (faction_id, code, name, email, lang, turn)" - " VALUES (?, ?, ?, ?, ?, ?)"; - sqlite3_stmt *stmt = 0; - strcpy(code, itoa36(f->no)); - sqlite3_prepare_v2(db, sql, -1, &stmt, 0); - sqlite3_bind_int(stmt, 1, f->subscription); - sqlite3_bind_text(stmt, 2, code, -1, SQLITE_STATIC); - sqlite3_bind_text(stmt, 3, f->name, -1, SQLITE_STATIC); - sqlite3_bind_text(stmt, 4, f->email, -1, SQLITE_STATIC); - sqlite3_bind_text(stmt, 5, locale_name(f->locale), -1, SQLITE_STATIC); - sqlite3_bind_int(stmt, 6, turn); - sqlite3_step(stmt); - sqlite3_finalize(stmt); -} - -struct cb_data { - const faction *f; - sqlite3 *db; - db_faction *dbf; -}; - -static bool db_faction_cb(void *el, void *arg) { - db_faction *df = (db_faction *)el; - struct cb_data *cb = (struct cb_data *)arg; - const faction *f = cb->f; - - if (f->no == df->no || strcmp(f->email, df->email) == 0 || strcmp(f->name, df->name) == 0) { - cb->dbf = df; - } - if (f->subscription == df->uid) { - cb->dbf = df; - return false; - } - return true; -} - -int db_update_factions(sqlite3 * db, bool force, int game_id) { - selist *ql = read_factions(db, game_id); - if (ql) { - faction *f; - struct cb_data cbdata; - cbdata.db = db; - cbdata.dbf = NULL; - sqlite3_exec(db, "BEGIN", 0, 0, 0); - for (f = factions; f; f = f->next) { - bool update = force; - cbdata.f = f; - selist_foreach_ex(ql, db_faction_cb, &cbdata); - if (cbdata.dbf) { - const db_faction *dbf = cbdata.dbf; - if (dbf->uid != f->subscription) { - log_warning("faction %s(%d) not found in database, but matches %d\n", itoa36(f->no), f->subscription, dbf->uid); - f->subscription = dbf->uid; - } - update = (dbf->no != f->no) || (strcmp(f->email, dbf->email) != 0) || (strcmp(f->name, dbf->name) != 0); - } - else { - f->subscription = insert_faction(db, game_id, f); - log_warning("faction %s not found in database, created as %d\n", itoa36(f->no), f->subscription); - update = true; - } - if (update) { - update_faction(db, f); - log_debug("faction %s updated\n", itoa36(f->no)); - } - } - sqlite3_exec(db, "COMMIT", 0, 0, 0); - } - return SQLITE_OK; -} - -int db_update_scores(sqlite3 * db, bool force) -{ - /* - const char *sselist_ins = - "INSERT OR FAIL INTO score (value,faction_id,turn) VALUES (?,?,?)"; - sqlite3_stmt *stmt_ins = stmt_cache_get(db, sselist_ins); - const char *sselist_upd = - "UPDATE score set value=? WHERE faction_id=? AND turn=?"; - sqlite3_stmt *stmt_upd = stmt_cache_get(db, sselist_upd); - faction *f; - sqlite3_exec(db, "BEGIN", 0, 0, 0); - for (f = factions; f; f = f->next) { - int res; - sqlite3_bind_int(stmt_ins, 1, f->score); - sqlite3_bind_int64(stmt_ins, 2, f->subscription); - sqlite3_bind_int(stmt_ins, 3, turn); - res = sqlite3_step(stmt_ins); - if (res == SQLITE_CONSTRAINT) { - sqlite3_bind_int(stmt_upd, 1, f->score); - sqlite3_bind_int64(stmt_upd, 2, f->subscription); - sqlite3_bind_int(stmt_upd, 3, turn); - res = sqlite3_step(stmt_upd); - sqlite3_reset(stmt_upd); - } - sqlite3_reset(stmt_ins); - } - sqlite3_exec(db, "COMMIT", 0, 0, 0); - */ - return SQLITE_OK; -} diff --git a/src/steal.c b/src/steal.c new file mode 100644 index 000000000..65316f1dd --- /dev/null +++ b/src/steal.c @@ -0,0 +1,248 @@ +/* +Copyright (c) 1998-2014, +Enno Rehling +Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifdef _MSC_VER +#include +#endif +#include +#include "economy.h" + +#include "laws.h" +#include "skill.h" +#include "study.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +void expandstealing(region * r, econ_request * stealorders) +{ + const resource_type *rsilver = get_resourcetype(R_SILVER); + unsigned int j; + unsigned int norders; + econ_request **requests; + + assert(rsilver); + + norders = expand_production(r, stealorders, &requests); + if (!norders) return; + + /* F�r jede unit in der Region wird Geld geklaut, wenn sie Opfer eines + * Beklauen-Orders ist. Jedes Opfer muss einzeln behandelt werden. + * + * u ist die beklaute unit. oa.unit ist die klauende unit. + */ + + for (j = 0; j != norders; j++) { + unit *u; + int n = 0; + + if (requests[j]->unit->n > requests[j]->unit->wants) { + break; + } + + u = findunitg(requests[j]->type.steal.no, r); + + if (u && u->region == r) { + n = get_pooled(u, rsilver, GET_ALL, INT_MAX); + } + if (n > 10 && rplane(r) && (rplane(r)->flags & PFL_NOALLIANCES)) { + /* In Questen nur reduziertes Klauen */ + n = 10; + } + if (n > 0) { + int w = requests[j]->unit->wants; + if (n > w) n = w; + use_pooled(u, rsilver, GET_ALL, n); + requests[j]->unit->n = n; + change_money(requests[j]->unit, n); + ADDMSG(&u->faction->msgs, msg_message("stealeffect", "unit region amount", + u, u->region, n)); + } + add_income(requests[j]->unit, IC_STEAL, requests[j]->unit->wants, requests[j]->unit->n); + fset(requests[j]->unit, UFL_LONGACTION | UFL_NOTMOVING); + } + free(requests); +} + +static int max_skill(region * r, struct faction * f, skill_t sk) +{ + unit *u; + int w = 0; + + for (u = r->units; u; u = u->next) { + if (u->faction == f) { + int effsk = effskill(u, sk, 0); + if (effsk > w) { + w = effsk; + } + } + } + + return w; +} + +message * steal_message(const unit * u, struct order *ord) { + plane *pl; + + if (fval(u_race(u), RCF_NOSTEAL)) { + return msg_feedback(u, ord, "race_nosteal", "race", u_race(u)); + } + + if (fval(u->region->terrain, SEA_REGION) && u_race(u) != get_race(RC_AQUARIAN)) { + return msg_feedback(u, ord, "error_onlandonly", ""); + } + + pl = rplane(u->region); + if (pl && fval(pl, PFL_NOATTACK)) { + return msg_feedback(u, ord, "error270", ""); + } + return 0; +} + +void steal_cmd(unit * u, struct order *ord, econ_request ** stealorders) +{ + const resource_type *rring = get_resourcetype(R_RING_OF_NIMBLEFINGER); + int n, i, id, effsk; + bool goblin = false; + econ_request *o; + unit *u2 = NULL; + region *r = u->region; + faction *f = NULL; + message * msg; + keyword_t kwd; + + kwd = init_order_depr(ord); + assert(kwd == K_STEAL); + + assert(skill_enabled(SK_PERCEPTION) && skill_enabled(SK_STEALTH)); + + msg = steal_message(u, ord); + if (msg) { + ADDMSG(&u->faction->msgs, msg); + return; + } + id = read_unitid(u->faction, r); + if (id > 0) { + u2 = findunitr(r, id); + } + if (u2 && u2->region == u->region) { + f = u2->faction; + } + else { + /* TODO: is this really necessary? it's the only time we use faction.c/deadhash + * it allows stealing from a unit in a dead faction, but why? */ + f = dfindhash(id); + } + + for (u2 = r->units; u2; u2 = u2->next) { + if (u2->faction == f && cansee(u->faction, r, u2, 0)) + break; + } + + if (!u2) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", + "")); + return; + } + + if (IsImmune(u2->faction)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "newbie_immunity_error", "turns", NewbieImmunity())); + return; + } + + if (u->faction->alliance && u->faction->alliance == u2->faction->alliance) { + cmistake(u, ord, 47, MSG_INCOME); + return; + } + + assert(u->region == u2->region); + if (!can_contact(r, u, u2)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error60", "")); + return; + } + + effsk = effskill(u, SK_STEALTH, 0); + n = effsk - max_skill(r, f, SK_PERCEPTION); + + if (n <= 0) { + /* Wahrnehmung == Tarnung */ + if (u_race(u) != get_race(RC_GOBLIN) || effsk <= 3) { + ADDMSG(&u->faction->msgs, msg_message("stealfail", "unit target", u, u2)); + if (n == 0) { + ADDMSG(&u2->faction->msgs, msg_message("stealdetect", "unit", u2)); + } + else { + ADDMSG(&u2->faction->msgs, msg_message("thiefdiscover", "unit target", + u, u2)); + } + return; + } + else { + ADDMSG(&u->faction->msgs, msg_message("stealfatal", "unit target", u, + u2)); + ADDMSG(&u2->faction->msgs, msg_message("thiefdiscover", "unit target", u, + u2)); + n = 1; + goblin = true; + } + } + + i = i_get(u->items, rring->itype); + if (i > u->number) i = u->number; + if (i > 0) { + n *= STEALINCOME * (u->number + i * (roqf_factor() - 1)); + } + else { + n *= u->number * STEALINCOME; + } + + u->wants = n; + + /* wer dank unsichtbarkeitsringen klauen kann, muss nicht unbedingt ein + * guter dieb sein, schliesslich macht man immer noch sehr viel laerm */ + + o = (econ_request *)calloc(1, sizeof(econ_request)); + o->unit = u; + o->qty = 1; /* Betrag steht in u->wants */ + o->type.steal.no = u2->no; + o->type.steal.goblin = goblin; /* Merken, wenn Goblin-Spezialklau */ + o->next = *stealorders; + *stealorders = o; + + /* Nur soviel PRODUCEEXP wie auch tatsaechlich gemacht wurde */ + if (n > u->number) n = u->number; + produceexp(u, SK_STEALTH, n); +} diff --git a/src/study.c b/src/study.c index 9d37a7648..09f228f45 100644 --- a/src/study.c +++ b/src/study.c @@ -16,10 +16,9 @@ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. **/ -#define TEACH_ALL 1 -#define TEACH_FRIENDS - +#ifdef _MSC_VER #include +#endif #include #include "study.h" #include "laws.h" @@ -47,12 +46,12 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* util includes */ #include #include -#include #include #include #include #include #include +#include #include #include @@ -65,6 +64,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include +#define TEACH_ALL 1 +#define TEACH_FRIENDS + static skill_t getskill(const struct locale *lang) { char token[128]; @@ -128,33 +130,45 @@ bool magic_lowskill(unit * u) /* ------------------------------------------------------------- */ -int study_cost(unit * u, skill_t sk) +int study_cost(struct unit *u, skill_t sk) { - static int cost[MAXSKILLS]; - int stufe, k = 50; + static int config; + static int costs[MAXSKILLS]; + int cost = -1; - if (cost[sk] == 0) { - char buffer[256]; - sprintf(buffer, "skills.cost.%s", skillnames[sk]); - cost[sk] = config_get_int(buffer, -1); - } - if (cost[sk] >= 0) { - return cost[sk]; + if (sk == SK_MAGIC) { + int next_level = 1 + (u ? get_level(u, sk) : 0); + /* Die Magiekosten betragen 50+Summe(50*Stufe) */ + /* 'Stufe' ist dabei die naechste zu erreichende Stufe */ + cost = config_get_int("skills.cost.magic", 50); + return cost * (1 + ((next_level + next_level * next_level) / 2)); } - switch (sk) { + else switch (sk) { case SK_SPY: - return 100; + cost = 100; + break; case SK_TACTICS: case SK_HERBALISM: case SK_ALCHEMY: - return 200; - case SK_MAGIC: /* Die Magiekosten betragen 50+Summe(50*Stufe) */ - /* 'Stufe' ist dabei die naechste zu erreichende Stufe */ - stufe = 1 + get_level(u, SK_MAGIC); - return k * (1 + ((stufe + 1) * stufe / 2)); + cost = 200; + break; default: - return 0; + cost = -1; + } + + if (config_changed(&config)) { + memset(costs, 0, sizeof(costs)); + } + + if (costs[sk] == 0) { + char buffer[256]; + sprintf(buffer, "skills.cost.%s", skillnames[sk]); + costs[sk] = config_get_int(buffer, cost); + } + if (costs[sk] >= 0) { + return costs[sk]; } + return (cost > 0) ? cost : 0; } /* ------------------------------------------------------------- */ @@ -215,7 +229,7 @@ teach_unit(unit * teacher, unit * student, int nteaching, skill_t sk, students -= teach->students; } - students = MIN(students, nteaching); + if (students > nteaching) students = nteaching; if (students > 0) { if (teach == NULL) { @@ -271,7 +285,7 @@ int teach_cmd(unit * teacher, struct order *ord) teaching = teacher->number * TEACHNUMBER; if ((i = get_effect(teacher, oldpotiontype[P_FOOL])) > 0) { /* Trank "Dumpfbackenbrot" */ - i = MIN(i, teacher->number * TEACHNUMBER); + if (i > teaching) i = teaching; /* Trank wirkt pro Schueler, nicht pro Lehrer */ teaching -= i; change_effect(teacher, oldpotiontype[P_FOOL], -i); @@ -283,7 +297,7 @@ int teach_cmd(unit * teacher, struct order *ord) count = 0; - init_order(ord); + init_order_depr(ord); #if TEACH_ALL if (getparam(teacher->faction->locale) == P_ANY) { @@ -304,7 +318,7 @@ int teach_cmd(unit * teacher, struct order *ord) else if (student->faction == teacher->faction) { if (getkeyword(student->thisorder) == K_STUDY) { /* Input ist nun von student->thisorder !! */ - init_order(student->thisorder); + init_order(student->thisorder, student->faction->locale); sk = getskill(student->faction->locale); if (sk != NOSKILL && teachskill[0] != NOSKILL) { for (t = 0; teachskill[t] != NOSKILL; ++t) { @@ -324,7 +338,7 @@ int teach_cmd(unit * teacher, struct order *ord) else if (alliedunit(teacher, student->faction, HELP_GUARD)) { if (getkeyword(student->thisorder) == K_STUDY) { /* Input ist nun von student->thisorder !! */ - init_order(student->thisorder); + init_order(student->thisorder, student->faction->locale); sk = getskill(student->faction->locale); if (sk != NOSKILL && effskill_study(teacher, sk, 0) - TEACHDIFFERENCE >= effskill(student, sk, 0)) { @@ -343,7 +357,7 @@ int teach_cmd(unit * teacher, struct order *ord) order *new_order; zOrder[0] = '\0'; - init_order(ord); + init_order_depr(ord); while (!parser_end()) { skill_t sk; @@ -361,7 +375,7 @@ int teach_cmd(unit * teacher, struct order *ord) const char *token; /* Finde den string, der den Fehler verursacht hat */ parser_pushstate(); - init_order(ord); + init_order_depr(ord); for (j = 0; j != count - 1; ++j) { /* skip over the first 'count' units */ @@ -396,7 +410,7 @@ int teach_cmd(unit * teacher, struct order *ord) strncat(zOrder, " ", sz - 1); --sz; } - sz -= strlcpy(zOrder + 4096 - sz, itoa36(student->no), sz); + sz -= str_strlcpy(zOrder + 4096 - sz, itoa36(student->no), sz); if (getkeyword(student->thisorder) != K_STUDY) { ADDMSG(&teacher->faction->msgs, @@ -406,7 +420,7 @@ int teach_cmd(unit * teacher, struct order *ord) /* Input ist nun von student->thisorder !! */ parser_pushstate(); - init_order(student->thisorder); + init_order(student->thisorder, student->faction->locale); sk = getskill(student->faction->locale); parser_popstate(); @@ -448,6 +462,7 @@ int teach_cmd(unit * teacher, struct order *ord) if (academy_students > 0 && sk_academy!=NOSKILL) { academy_teaching_bonus(teacher, sk_academy, academy_students); } + init_order_depr(NULL); return 0; } @@ -553,27 +568,27 @@ int study_cmd(unit * u, order * ord) if (!unit_can_study(u)) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_race_nolearn", "race", u_race(u))); - return 0; + return -1; } - init_order(ord); + (void)init_order(ord, u->faction->locale); sk = getskill(u->faction->locale); if (sk < 0) { cmistake(u, ord, 77, MSG_EVENT); - return 0; + return -1; } /* Hack: Talente mit Malus -99 koennen nicht gelernt werden */ if (u_race(u)->bonus[sk] == -99) { cmistake(u, ord, 771, MSG_EVENT); - return 0; + return -1; } if (!learn_newskills) { skill *sv = unit_skill(u, sk); if (sv == NULL) { /* we can only learn skills we already have */ cmistake(u, ord, 771, MSG_EVENT); - return 0; + return -1; } } @@ -581,7 +596,7 @@ int study_cmd(unit * u, order * ord) if (u_race(u) == rc_snotling) { if (get_level(u, sk) >= 8) { cmistake(u, ord, 308, MSG_EVENT); - return 0; + return -1; } } @@ -597,17 +612,18 @@ int study_cmd(unit * u, order * ord) if (studycost > 0 && !ExpensiveMigrants() && is_migrant(u)) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_migrants_nolearn", "")); - return 0; + return -1; } /* Akademie: */ if (active_building(u, bt_find("academy"))) { - studycost = MAX(50, studycost * 2); + studycost = studycost * 2; + if (studycost < 50) studycost = 50; } if (sk == SK_MAGIC) { if (u->number > 1) { cmistake(u, ord, 106, MSG_MAGIC); - return 0; + return -1; } if (is_familiar(u)) { /* Vertraute zaehlen nicht zu den Magiern einer Partei, @@ -620,7 +636,7 @@ int study_cmd(unit * u, order * ord) if (count_skill(u->faction, SK_MAGIC) + u->number > mmax) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_max_magicians", "amount", mmax)); - return 0; + return -1; } mtyp = getmagicskill(u->faction->locale); if (mtyp == M_NONE || mtyp == M_GRAY) { @@ -635,7 +651,7 @@ int study_cmd(unit * u, order * ord) mtyp = getmagicskill(u->faction->locale); if (mtyp == M_NONE) { cmistake(u, ord, 178, MSG_MAGIC); - return 0; + return -1; } } } @@ -644,7 +660,7 @@ int study_cmd(unit * u, order * ord) * als das der Partei */ if (u->faction->magiegebiet != 0) { cmistake(u, ord, 179, MSG_MAGIC); - return 0; + return -1; } else { /* Lernt zum ersten mal Magie und legt damit das @@ -663,7 +679,7 @@ int study_cmd(unit * u, order * ord) mtyp = getmagicskill(u->faction->locale); if (mtyp == M_NONE) { cmistake(u, ord, 178, MSG_MAGIC); - return 0; + return -1; } } /* Legt damit das Magiegebiet der Partei fest */ @@ -678,18 +694,18 @@ int study_cmd(unit * u, order * ord) if (count_skill(u->faction, SK_ALCHEMY) + u->number > amax) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_max_alchemists", "amount", amax)); - return 0; + return -1; } } } if (studycost) { int cost = studycost * u->number; money = get_pooled(u, get_resourcetype(R_SILVER), GET_DEFAULT, cost); - money = MIN(money, cost); + if (money > cost) money = cost; } if (money < studycost * u->number) { studycost = p; /* Ohne Univertreurung */ - money = MIN(money, studycost); + if (money > studycost) money = studycost; if (p > 0 && money < studycost * u->number) { cmistake(u, ord, 65, MSG_EVENT); multi = money / (double)(studycost * u->number); @@ -709,12 +725,14 @@ int study_cmd(unit * u, order * ord) } if (get_effect(u, oldpotiontype[P_WISE])) { - l = MIN(u->number, get_effect(u, oldpotiontype[P_WISE])); + l = get_effect(u, oldpotiontype[P_WISE]); + if (l > u->number) l = u->number; teach->days += l * EXPERIENCEDAYS; change_effect(u, oldpotiontype[P_WISE], -l); } if (get_effect(u, oldpotiontype[P_FOOL])) { - l = MIN(u->number, get_effect(u, oldpotiontype[P_FOOL])); + l = get_effect(u, oldpotiontype[P_FOOL]); + if (l > u->number) l = u->number; teach->days -= l * STUDYDAYS; change_effect(u, oldpotiontype[P_FOOL], -l); } @@ -761,21 +779,10 @@ int study_cmd(unit * u, order * ord) /* Spruchlistenaktualiesierung ist in Regeneration */ if (sk == SK_ALCHEMY) { - const potion_type *ptype; faction *f = u->faction; int skill = effskill(u, SK_ALCHEMY, 0); if (skill > maxalchemy) { - for (ptype = potiontypes; ptype; ptype = ptype->next) { - if (skill == ptype->level * 2) { - attrib *a = a_find(f->attribs, &at_showitem); - while (a && a->type == &at_showitem && a->data.v != ptype) - a = a->next; - if (a == NULL || a->type != &at_showitem) { - a = a_add(&f->attribs, a_new(&at_showitem)); - a->data.v = (void *)ptype->itype; - } - } - } + show_potions(f, skill); } } else if (sk == SK_MAGIC) { @@ -784,7 +791,7 @@ int study_cmd(unit * u, order * ord) mage = create_mage(u, u->faction->magiegebiet); } } - + init_order_depr(NULL); return 0; } @@ -810,23 +817,22 @@ void produceexp(struct unit *u, skill_t sk, int n) produceexp_ex(u, sk, n, learn_skill); } -#ifndef NO_TESTS static learn_fun inject_learn_fun = 0; void inject_learn(learn_fun fun) { inject_learn_fun = fun; } -#endif + /** days should be scaled by u->number; STUDYDAYS * u->number is one week worth of learning */ void learn_skill(unit *u, skill_t sk, int days) { int leveldays = STUDYDAYS * u->number; int weeks = 0; -#ifndef NO_TESTS + + assert(sk >= 0 && sk < MAXSKILLS); if (inject_learn_fun) { inject_learn_fun(u, sk, days); return; } -#endif while (days >= leveldays) { ++weeks; days -= leveldays; @@ -861,19 +867,28 @@ void reduce_skill_days(unit *u, skill_t sk, int days) { void demon_skillchange(unit *u) { skill *sv = u->skills; - int upchance = 15; - int downchance = 10; + int upchance = 15, downchance = 10; + static int config; + static bool rule_hunger; + static int cfgup, cfgdown; + + if (config_changed(&config)) { + rule_hunger = config_get_int("hunger.demon.skills", 0) != 0; + cfgup = config_get_int("skillchange.demon.up", 15); + cfgdown = config_get_int("skillchange.demon.down", 10); + } + if (cfgup == 0) { + /* feature is disabled */ + return; + } + upchance = cfgup; + downchance = cfgdown; if (fval(u, UFL_HUNGER)) { /* hungry demons only go down, never up in skill */ - static int config; - static bool rule_hunger; - if (config_changed(&config)) { - rule_hunger = config_get_int("hunger.demon.skill", 0) != 0; - } if (rule_hunger) { + downchance = upchance; upchance = 0; - downchance = 15; } } diff --git a/src/study.h b/src/study.h index ff43f1f43..b4b76bb8c 100644 --- a/src/study.h +++ b/src/study.h @@ -56,9 +56,7 @@ extern "C" { extern const struct attrib_type at_learning; -#ifndef NO_TESTS void inject_learn(learn_fun fun); -#endif #ifdef __cplusplus } diff --git a/src/study.test.c b/src/study.test.c index 75c169b74..b89d0ed07 100644 --- a/src/study.test.c +++ b/src/study.test.c @@ -57,6 +57,12 @@ typedef struct { unit *teachers[2]; } study_fixture; +static void setup_study(void) { + mt_register(mt_new_va("studycost", "unit:unit", "region:region", "cost:int", "skill:int", NULL)); + mt_register(mt_new_va("teach_teacher", "teacher:unit", "student:unit", "skill:int", "level:int", NULL)); + mt_register(mt_new_va("teach_student", "teacher:unit", "student:unit", "skill:int", NULL)); +} + static void setup_locale(struct locale *lang) { int i; for (i = 0; i < MAXSKILLS; ++i) { @@ -66,7 +72,7 @@ static void setup_locale(struct locale *lang) { init_skills(lang); } -static void setup_study(study_fixture *fix, skill_t sk) { +static void setup_teacher(study_fixture *fix, skill_t sk) { struct region * r; struct faction *f; struct locale *lang; @@ -74,8 +80,8 @@ static void setup_study(study_fixture *fix, skill_t sk) { assert(fix); test_setup(); config_set("study.random_progress", "0"); - r = test_create_region(0, 0, 0); - f = test_create_faction(0); + r = test_create_region(0, 0, NULL); + f = test_create_faction(NULL); f->locale = lang = test_create_locale(); setup_locale(lang); fix->u = test_create_unit(f, r); @@ -96,20 +102,20 @@ static void test_study_no_teacher(CuTest *tc) { study_fixture fix; skill *sv; - setup_study(&fix, SK_CROSSBOW); + setup_teacher(&fix, SK_CROSSBOW); study_cmd(fix.u, fix.u->thisorder); CuAssertPtrNotNull(tc, sv = unit_skill(fix.u, SK_CROSSBOW)); CuAssertIntEquals(tc, 1, sv->level); CuAssertIntEquals(tc, 2, sv->weeks); CuAssertPtrEquals(tc, 0, test_get_last_message(fix.u->faction->msgs)); - test_cleanup(); + test_teardown(); } static void test_study_with_teacher(CuTest *tc) { study_fixture fix; skill *sv; - setup_study(&fix, SK_CROSSBOW); + setup_teacher(&fix, SK_CROSSBOW); set_level(fix.teachers[0], SK_CROSSBOW, TEACHDIFFERENCE); teach_cmd(fix.teachers[0], fix.teachers[0]->thisorder); CuAssertPtrEquals(tc, 0, test_get_last_message(fix.u->faction->msgs)); @@ -117,21 +123,21 @@ static void test_study_with_teacher(CuTest *tc) { CuAssertPtrNotNull(tc, sv = unit_skill(fix.u, SK_CROSSBOW)); CuAssertIntEquals(tc, 1, sv->level); CuAssertIntEquals(tc, 1, sv->weeks); - test_cleanup(); + test_teardown(); } static void test_study_with_bad_teacher(CuTest *tc) { study_fixture fix; skill *sv; - setup_study(&fix, SK_CROSSBOW); + setup_teacher(&fix, SK_CROSSBOW); teach_cmd(fix.teachers[0], fix.teachers[0]->thisorder); CuAssertPtrNotNull(tc, test_find_messagetype(fix.u->faction->msgs, "teach_asgood")); study_cmd(fix.u, fix.u->thisorder); CuAssertPtrNotNull(tc, sv = unit_skill(fix.u, SK_CROSSBOW)); CuAssertIntEquals(tc, 1, sv->level); CuAssertIntEquals(tc, 2, sv->weeks); - test_cleanup(); + test_teardown(); } static void test_study_bug_2194(CuTest *tc) { @@ -144,7 +150,7 @@ static void test_study_bug_2194(CuTest *tc) { init_resources(); loc = test_create_locale(); setup_locale(loc); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); scale_number(u, 2); set_level(u, SK_CROSSBOW, TEACHDIFFERENCE); u->faction->locale = loc; @@ -177,7 +183,7 @@ static void test_study_bug_2194(CuTest *tc) { teach_cmd(u, u->thisorder); learn_reset(); CuAssertIntEquals(tc, 0, log_size); - test_cleanup(); + test_teardown(); } static CuTest *g_tc; @@ -197,12 +203,12 @@ static void test_produceexp(CuTest *tc) { g_tc = tc; test_setup(); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); scale_number(u, 2); config_set("study.produceexp", "20"); produceexp_ex(u, SK_ALCHEMY, 1, cb_learn_one); produceexp_ex(u, SK_ALCHEMY, 2, cb_learn_two); - test_cleanup(); + test_teardown(); } static void test_academy_building(CuTest *tc) { @@ -212,13 +218,13 @@ static void test_academy_building(CuTest *tc) { message * msg; test_setup(); - mt_register(mt_new_va("teach_asgood", "unit:unit", "region:region", "command:order", "student:unit", 0)); + mt_register(mt_new_va("teach_asgood", "unit:unit", "region:region", "command:order", "student:unit", NULL)); random_source_inject_constant(0.0); init_resources(); loc = test_create_locale(); setup_locale(loc); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); scale_number(u, 2); set_level(u, SK_CROSSBOW, TEACHDIFFERENCE); u->faction->locale = loc; @@ -248,7 +254,7 @@ static void test_academy_building(CuTest *tc) { CuAssertPtrEquals(tc, u, log_learners[0].u); CuAssertIntEquals(tc, SK_CROSSBOW, log_learners[0].sk); CuAssertIntEquals(tc, u1->number, log_learners[0].days); - test_cleanup(); + test_teardown(); } /* @@ -262,15 +268,16 @@ static void test_academy_bonus(CuTest *tc) { building * b; test_setup(); + setup_study(); random_source_inject_constant(0.0); init_resources(); loc = test_create_locale(); setup_locale(loc); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); u->faction->locale = loc; - u0 = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + u0 = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); set_level(u, SK_CROSSBOW, TEACHDIFFERENCE); set_level(u0, SK_CROSSBOW, TEACHDIFFERENCE); @@ -311,7 +318,7 @@ static void test_academy_bonus(CuTest *tc) { CuAssertPtrEquals(tc, u3, log_learners[3].u); CuAssertIntEquals(tc, 160, log_learners[3].days); learn_reset(); - test_cleanup(); + test_teardown(); } void test_learn_skill_single(CuTest *tc) { @@ -319,7 +326,7 @@ void test_learn_skill_single(CuTest *tc) { skill *sv; test_setup(); config_set("study.random_progress", "0"); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); learn_skill(u, SK_ALCHEMY, STUDYDAYS); CuAssertPtrNotNull(tc, sv = u->skills); CuAssertIntEquals(tc, SK_ALCHEMY, sv->id); @@ -330,7 +337,7 @@ void test_learn_skill_single(CuTest *tc) { learn_skill(u, SK_ALCHEMY, STUDYDAYS * 2); CuAssertIntEquals(tc, 2, sv->level); CuAssertIntEquals(tc, 2, sv->weeks); - test_cleanup(); + test_teardown(); } void test_learn_skill_multi(CuTest *tc) { @@ -338,7 +345,7 @@ void test_learn_skill_multi(CuTest *tc) { skill *sv; test_setup(); config_set("study.random_progress", "0"); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); scale_number(u, 10); learn_skill(u, SK_ALCHEMY, STUDYDAYS * u->number); CuAssertPtrNotNull(tc, sv = u->skills); @@ -350,7 +357,7 @@ void test_learn_skill_multi(CuTest *tc) { learn_skill(u, SK_ALCHEMY, STUDYDAYS * u->number * 2); CuAssertIntEquals(tc, 2, sv->level); CuAssertIntEquals(tc, 2, sv->weeks); - test_cleanup(); + test_teardown(); } static void test_demon_skillchanges(CuTest *tc) { @@ -359,19 +366,19 @@ static void test_demon_skillchanges(CuTest *tc) { test_setup(); rc = test_create_race("demon"); CuAssertPtrEquals(tc, (void *)rc, (void *)get_race(RC_DAEMON)); - u = test_create_unit(test_create_faction(rc), test_create_region(0, 0, 0)); + u = test_create_unit(test_create_faction(rc), test_create_region(0, 0, NULL)); CuAssertPtrNotNull(tc, u); set_level(u, SK_CROSSBOW, 1); demon_skillchange(u); /* TODO: sensing here */ - test_cleanup(); + test_teardown(); } static void test_study_cmd(CuTest *tc) { unit *u; test_setup(); init_resources(); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); u->thisorder = create_order(K_STUDY, u->faction->locale, "CROSSBOW"); learn_inject(); study_cmd(u, u->thisorder); @@ -379,49 +386,66 @@ static void test_study_cmd(CuTest *tc) { CuAssertPtrEquals(tc, u, log_learners[0].u); CuAssertIntEquals(tc, SK_CROSSBOW, log_learners[0].sk); CuAssertIntEquals(tc, STUDYDAYS, log_learners[0].days); - test_cleanup(); + test_teardown(); } static void test_study_magic(CuTest *tc) { unit *u; faction *f; const struct locale *lang; - const struct resource_type *rtype; + const struct item_type *itype; test_setup(); + setup_study(); init_resources(); - f = test_create_faction(0); - u = test_create_unit(f, test_create_region(0, 0, 0)); + f = test_create_faction(NULL); lang = f->locale; - CuAssertPtrNotNull(tc, rtype = get_resourcetype(R_SILVER)); + u = test_create_unit(f, test_create_region(0, 0, NULL)); u->thisorder = create_order(K_STUDY, lang, "%s", skillnames[SK_MAGIC]); - study_cmd(u, u->thisorder); + itype = test_create_silver(); + + CuAssertIntEquals(tc, -1, study_cmd(u, u->thisorder)); CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error178")); free_order(u->thisorder); test_clear_messages(f); u->thisorder = create_order(K_STUDY, lang, "%s %s", skillnames[SK_MAGIC], magic_school[M_GWYRRD]); - study_cmd(u, u->thisorder); + CuAssertIntEquals(tc, 0, study_cmd(u, u->thisorder)); CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error65")); test_clear_messages(f); - i_change(&u->items, rtype->itype, 100); - study_cmd(u, u->thisorder); + i_change(&u->items, itype, 100); + CuAssertIntEquals(tc, 0, study_cmd(u, u->thisorder)); CuAssertIntEquals(tc, M_GWYRRD, f->magiegebiet); - CuAssertIntEquals(tc, 0, i_get(u->items, rtype->itype)); + CuAssertIntEquals(tc, 0, i_get(u->items, itype)); CuAssertPtrNotNull(tc, get_mage_depr(u)); CuAssertPtrEquals(tc, 0, test_find_messagetype(f->msgs, "error65")); CuAssertIntEquals(tc, M_GWYRRD, get_mage_depr(u)->magietyp); - /* TODO: the static cost array in study_cost prevents this test: - test_clear_messages(f); - config_set("skills.cost.magic", "50"); - i_change(&u->items, rtype->itype, 50); - study_cmd(u, u->thisorder); - CuAssertPtrEquals(tc, 0, test_find_messagetype(f->msgs, "error65")); - */ + test_teardown(); +} - test_cleanup(); +static void test_study_cost_magic(CuTest *tc) { + unit * u; + + test_setup(); + setup_study(); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); + + CuAssertIntEquals(tc, 100, study_cost(u, SK_MAGIC)); + set_level(u, SK_MAGIC, 1); + CuAssertIntEquals(tc, 200, study_cost(u, SK_MAGIC)); + set_level(u, SK_MAGIC, 2); + CuAssertIntEquals(tc, 350, study_cost(u, SK_MAGIC)); + set_level(u, SK_MAGIC, 29); + CuAssertIntEquals(tc, 23300, study_cost(u, SK_MAGIC)); + set_level(u, SK_MAGIC, 27); + CuAssertIntEquals(tc, 20350, study_cost(u, SK_MAGIC)); + + config_set("skills.cost.magic", "100"); + CuAssertIntEquals(tc, 2*20350, study_cost(u, SK_MAGIC)); + + test_teardown(); } static void test_study_cost(CuTest *tc) { @@ -429,11 +453,17 @@ static void test_study_cost(CuTest *tc) { const struct item_type *itype; test_setup(); - init_resources(); - itype = get_resourcetype(R_SILVER)->itype; - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + setup_study(); + + itype = test_create_silver(); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); scale_number(u, 2); u->thisorder = create_order(K_STUDY, u->faction->locale, skillnames[SK_ALCHEMY]); + + CuAssertIntEquals(tc, 200, study_cost(u, SK_ALCHEMY)); + config_set("skills.cost.alchemy", "50"); + CuAssertIntEquals(tc, 50, study_cost(u, SK_ALCHEMY)); + i_change(&u->items, itype, u->number * study_cost(u, SK_ALCHEMY)); learn_inject(); study_cmd(u, u->thisorder); @@ -442,7 +472,7 @@ static void test_study_cost(CuTest *tc) { CuAssertIntEquals(tc, SK_ALCHEMY, log_learners[0].sk); CuAssertIntEquals(tc, STUDYDAYS * u->number, log_learners[0].days); CuAssertIntEquals(tc, 0, i_get(u->items, itype)); - test_cleanup(); + test_teardown(); } static void test_teach_magic(CuTest *tc) { @@ -451,11 +481,12 @@ static void test_teach_magic(CuTest *tc) { const struct item_type *itype; test_setup(); + setup_study(); init_resources(); itype = get_resourcetype(R_SILVER)->itype; - f = test_create_faction(0); + f = test_create_faction(NULL); f->magiegebiet = M_GWYRRD; - u = test_create_unit(f, test_create_region(0, 0, 0)); + u = test_create_unit(f, test_create_region(0, 0, NULL)); u->thisorder = create_order(K_STUDY, f->locale, "%s", skillnames[SK_MAGIC]); i_change(&u->items, itype, study_cost(u, SK_MAGIC)); ut = test_create_unit(f, u->region); @@ -470,14 +501,14 @@ static void test_teach_magic(CuTest *tc) { CuAssertIntEquals(tc, SK_MAGIC, log_learners[0].sk); CuAssertIntEquals(tc, STUDYDAYS * 2, log_learners[0].days); CuAssertIntEquals(tc, 0, i_get(u->items, itype)); - test_cleanup(); + test_teardown(); } static void test_teach_cmd(CuTest *tc) { unit *u, *ut; test_setup(); init_resources(); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); scale_number(u, 10); u->thisorder = create_order(K_STUDY, u->faction->locale, "CROSSBOW"); ut = test_create_unit(u->faction, u->region); @@ -490,14 +521,14 @@ static void test_teach_cmd(CuTest *tc) { CuAssertPtrEquals(tc, u, log_learners[0].u); CuAssertIntEquals(tc, SK_CROSSBOW, log_learners[0].sk); CuAssertIntEquals(tc, STUDYDAYS * 2 * u->number, log_learners[0].days); - test_cleanup(); + test_teardown(); } static void test_teach_two(CuTest *tc) { unit *u1, *u2, *ut; test_setup(); init_resources(); - u1 = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + u1 = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); scale_number(u1, 5); u1->thisorder = create_order(K_STUDY, u1->faction->locale, "CROSSBOW"); u2 = test_create_unit(u1->faction, u1->region); @@ -517,7 +548,7 @@ static void test_teach_two(CuTest *tc) { CuAssertPtrEquals(tc, u2, log_learners[1].u); CuAssertIntEquals(tc, SK_CROSSBOW, log_learners[1].sk); CuAssertIntEquals(tc, STUDYDAYS * 2 * u2->number, log_learners[1].days); - test_cleanup(); + test_teardown(); } static void test_teach_two_skills(CuTest *tc) { @@ -527,8 +558,8 @@ static void test_teach_two_skills(CuTest *tc) { test_setup(); init_resources(); - f = test_create_faction(0); - r = test_create_region(0, 0, 0); + f = test_create_faction(NULL); + r = test_create_region(0, 0, NULL); u1 = test_create_unit(f, r); scale_number(u1, 5); u1->thisorder = create_order(K_STUDY, f->locale, "CROSSBOW"); @@ -550,14 +581,14 @@ static void test_teach_two_skills(CuTest *tc) { CuAssertPtrEquals(tc, u2, log_learners[1].u); CuAssertIntEquals(tc, SK_ENTERTAINMENT, log_learners[1].sk); CuAssertIntEquals(tc, STUDYDAYS * 2 * u2->number, log_learners[1].days); - test_cleanup(); + test_teardown(); } static void test_teach_one_to_many(CuTest *tc) { unit *u, *ut; test_setup(); init_resources(); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); scale_number(u, 20); u->thisorder = create_order(K_STUDY, u->faction->locale, "CROSSBOW"); ut = test_create_unit(u->faction, u->region); @@ -570,7 +601,7 @@ static void test_teach_one_to_many(CuTest *tc) { CuAssertPtrEquals(tc, u, log_learners[0].u); CuAssertIntEquals(tc, SK_CROSSBOW, log_learners[0].sk); CuAssertIntEquals(tc, STUDYDAYS * 10 + STUDYDAYS * u->number, log_learners[0].days); - test_cleanup(); + test_teardown(); } static void test_teach_many_to_one(CuTest *tc) { @@ -578,7 +609,7 @@ static void test_teach_many_to_one(CuTest *tc) { test_setup(); init_resources(); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); scale_number(u, 20); u->thisorder = create_order(K_STUDY, u->faction->locale, "CROSSBOW"); u1 = test_create_unit(u->faction, u->region); @@ -595,7 +626,7 @@ static void test_teach_many_to_one(CuTest *tc) { CuAssertPtrEquals(tc, u, log_learners[0].u); CuAssertIntEquals(tc, SK_CROSSBOW, log_learners[0].sk); CuAssertIntEquals(tc, 2 * STUDYDAYS * u->number, log_learners[0].days); - test_cleanup(); + test_teardown(); } static void test_teach_message(CuTest *tc) { @@ -605,14 +636,16 @@ static void test_teach_message(CuTest *tc) { teaching_info *teach; test_setup(); + mt_register(mt_new_va("teach_teacher", "teacher:unit", "student:unit", "skill:int", "level:int", NULL)); + mt_register(mt_new_va("teach_student", "teacher:unit", "student:unit", "skill:int", NULL)); init_resources(); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); scale_number(u, 20); u->thisorder = create_order(K_STUDY, u->faction->locale, "CROSSBOW"); - u1 = test_create_unit(test_create_faction(0), u->region); + u1 = test_create_unit(test_create_faction(NULL), u->region); set_level(u1, SK_CROSSBOW, TEACHDIFFERENCE); u1->thisorder = create_order(K_TEACH, u->faction->locale, itoa36(u->no)); - u2 = test_create_unit(test_create_faction(0), u->region); + u2 = test_create_unit(test_create_faction(NULL), u->region); al = ally_add(&u->faction->allies, u2->faction); al->status = HELP_GUARD; set_level(u2, SK_CROSSBOW, TEACHDIFFERENCE); @@ -636,7 +669,7 @@ static void test_teach_message(CuTest *tc) { CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "teach_student")); a = a_find(u->attribs, &at_learning); CuAssertPtrEquals(tc, NULL, a); - test_cleanup(); + test_teardown(); } static void test_teach_many_to_many(CuTest *tc) { @@ -646,8 +679,8 @@ static void test_teach_many_to_many(CuTest *tc) { test_setup(); init_resources(); - f = test_create_faction(0); - r = test_create_region(0, 0, 0); + f = test_create_faction(NULL); + r = test_create_region(0, 0, NULL); s1 = test_create_unit(f, r); scale_number(s1, 20); s1->thisorder = create_order(K_STUDY, f->locale, "CROSSBOW"); @@ -674,7 +707,7 @@ static void test_teach_many_to_many(CuTest *tc) { CuAssertPtrEquals(tc, s2, log_learners[1].u); CuAssertIntEquals(tc, SK_CROSSBOW, log_learners[1].sk); CuAssertIntEquals(tc, 2 * STUDYDAYS * s2->number, log_learners[1].days); - test_cleanup(); + test_teardown(); } CuSuite *get_study_suite(void) @@ -682,6 +715,7 @@ CuSuite *get_study_suite(void) CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_study_cmd); SUITE_ADD_TEST(suite, test_study_cost); + SUITE_ADD_TEST(suite, test_study_cost_magic); SUITE_ADD_TEST(suite, test_study_magic); SUITE_ADD_TEST(suite, test_teach_cmd); SUITE_ADD_TEST(suite, test_teach_magic); diff --git a/src/summary.c b/src/summary.c index 916124815..79ffd1b6d 100644 --- a/src/summary.c +++ b/src/summary.c @@ -8,8 +8,9 @@ * */ -/* wenn platform.h nicht vor curses included wird, kompiliert es unter windows nicht */ +#ifdef _MSC_VER #include +#endif #include #include "summary.h" @@ -30,6 +31,8 @@ #include #include #include +#include +#include #include #include @@ -50,8 +53,8 @@ typedef struct summary { int peasants; int nunits; int playerpop; - double playermoney; - double peasantmoney; + long long int playermoney; + long long int peasantmoney; int armed_men; int poprace[MAXRACES]; int factionrace[MAXRACES]; @@ -88,7 +91,7 @@ int update_nmrs(void) } for (f = factions; f; f = f->next) { - if (fval(f, FFL_ISNEW)) { + if (f->age<=1) { ++newplayers; } else if (!fval(f, FFL_NOIDLEOUT|FFL_CURSED)) { @@ -96,8 +99,8 @@ int update_nmrs(void) if (timeout>0) { if (nmr < 0 || nmr > timeout) { log_error("faction %s has %d NMR", itoa36(f->no), nmr); - nmr = MAX(0, nmr); - nmr = MIN(nmr, timeout); + if (nmr < 0) nmr = 0; + if (nmr > timeout) nmr = timeout; } if (nmr > 0) { log_debug("faction %s has %d NMR", itoa36(f->no), nmr); @@ -109,22 +112,6 @@ int update_nmrs(void) return newplayers; } -static char *pcomp(double i, double j) -{ - static char buf[32]; - sprintf(buf, "%.0f (%s%.0f)", i, (i >= j) ? "+" : "", i - j); - return buf; -} - -static char *rcomp(int i, int j) -{ - static char buf[32]; - sprintf(buf, "%d (%s%d,%s%d%%)", - i, (i >= j) ? "+" : "", i - j, (i >= j) ? "+" : "", - j ? ((i - j) * 100) / j : 0); - return buf; -} - static void out_faction(FILE * file, const struct faction *f) { if (alliances != NULL) { @@ -165,7 +152,7 @@ static void writeturn(void) char zText[4096]; FILE *f; - join_path(basepath(), "datum", zText, sizeof(zText)); + path_join(basepath(), "datum", zText, sizeof(zText)); f = fopen(zText, "w"); if (!f) { perror(zText); @@ -173,7 +160,7 @@ static void writeturn(void) } fputs(gamedate2(default_locale), f); fclose(f); - join_path(basepath(), "turn", zText, sizeof(zText)); + path_join(basepath(), "turn", zText, sizeof(zText)); f = fopen(zText, "w"); if (!f) { perror(zText); @@ -183,19 +170,82 @@ static void writeturn(void) fclose(f); } -void report_summary(summary * s, summary * o, bool full) +static int count_umlaut(const char *s) +{ + int result = 0; + const char *cp; + for (cp = s; *cp; ++cp) { + ucs4_t ucs = *cp; + if (ucs & 0x80) { + size_t size; + ++result; + unicode_utf8_to_ucs4(&ucs, cp, &size); + cp += size; + } + } + return result; +} + +static void summarize_races(const summary *s, FILE *F, bool full) { + int i; + for (i = 0; i < MAXRACES; i++) { + if (s->poprace[i] > 0) { + const char *pad = " "; + int lpad = (int)strlen(pad); + const race *rc = get_race(i); + const char *rcname = LOC(default_locale, rc_name_s(rc, NAME_PLURAL)); + lpad -= count_umlaut(rcname); + assert(lpad >= 0); + if (full) { + fputs(pad + lpad, F); + fprintf(F, "%20s: ", rcname); + fprintf(F, "%8d\n", s->poprace[i]); + } + else if (i != RC_TEMPLATE && i != RC_CLONE) { + if (playerrace(rc)) { + fputs(pad + lpad, F); + fprintf(F, "%16s: ", rcname); + fprintf(F, "%8d\n", s->poprace[i]); + } + } + } + } +} + +static void summarize_players(const summary *s, FILE *F) { + int i; + const char * suffix = LOC(default_locale, "stat_tribe_p"); + + for (i = 0; i < MAXRACES; i++) { + if (i != RC_TEMPLATE && i != RC_CLONE && s->factionrace[i]) { + const race *rc = get_race(i); + if (rc && playerrace(rc)) { + const char * pad = " "; + int lpad = (int)strlen(pad); + const char *rccat = LOC(default_locale, rc_name_s(rc, NAME_CATEGORY)); + lpad -= count_umlaut(rccat); + assert(lpad >= 0); + fputs(pad + lpad, F); + fprintf(F, "%16s%s:", rccat, suffix); + fprintf(F, "%8d\n", s->factionrace[i]); + } + } + } +} + +void report_summary(const summary * s, bool full) { FILE *F = NULL; - int i, newplayers = 0; + int newplayers = 0; faction *f; char zText[4096]; int timeout = NMRTimeout(); if (full) { - join_path(basepath(), "parteien.full", zText, sizeof(zText)); + path_join(basepath(), "parteien.full", zText, sizeof(zText)); } else { - join_path(basepath(), "parteien", zText, sizeof(zText)); + path_join(basepath(), "parteien", zText, sizeof(zText)); } F = fopen(zText, "w"); if (!F) { @@ -210,120 +260,82 @@ void report_summary(summary * s, summary * o, bool full) #endif log_info("writing summary to file: parteien.\n"); fprintf(F, "%s\n%s\n\n", game_name(), gamedate2(default_locale)); - fprintf(F, "Auswertung Nr: %d\n\n", turn); - fprintf(F, "Parteien: %s\n", pcomp(s->factions, o->factions)); - fprintf(F, "Einheiten: %s\n", pcomp(s->nunits, o->nunits)); - fprintf(F, "Spielerpopulation: %s\n", pcomp(s->playerpop, o->playerpop)); - fprintf(F, " davon bewaffnet: %s\n", pcomp(s->armed_men, o->armed_men)); - fprintf(F, " Helden: %s\n", pcomp(s->heroes, o->heroes)); + fprintf(F, "Auswertung Nr: %8d\n\n", turn); + fprintf(F, "Parteien: %8d\n", s->factions); + fprintf(F, "Einheiten: %8d\n", s->nunits); + fprintf(F, "Spielerpopulation: %8d\n", s->playerpop); + fprintf(F, " davon bewaffnet: %8d\n", s->armed_men); + fprintf(F, " Helden: %8d\n", s->heroes); if (full) { - fprintf(F, "Regionen: %d\n", (int)listlen(regions)); - fprintf(F, "Bewohnte Regionen: %d\n", s->inhabitedregions); - fprintf(F, "Landregionen: %d\n", s->landregionen); - fprintf(F, "Spielerregionen: %d\n", s->regionen_mit_spielern); - fprintf(F, "Landspielerregionen: %d\n", s->landregionen_mit_spielern); - fprintf(F, "Inaktive Vulkane: %d\n", s->inactive_volcanos); - fprintf(F, "Aktive Vulkane: %d\n\n", s->active_volcanos); + fprintf(F, "Regionen: %8d\n", (int)listlen(regions)); + fprintf(F, "Bewohnte Regionen: %8d\n", s->inhabitedregions); + fprintf(F, "Landregionen: %8d\n", s->landregionen); + fprintf(F, "Spielerregionen: %8d\n", s->regionen_mit_spielern); + fprintf(F, "Landspielerregionen: %8d\n", s->landregionen_mit_spielern); + fprintf(F, "Inaktive Vulkane: %8d\n", s->inactive_volcanos); + fprintf(F, "Aktive Vulkane: %8d\n\n", s->active_volcanos); } - for (i = 0; i < MAXRACES; i++) { - if (i != RC_TEMPLATE && i != RC_CLONE && s->factionrace[i]) { - const race *rc = get_race(i); - if (rc && playerrace(rc)) { - fprintf(F, "%13s%s: %s\n", LOC(default_locale, rc_name_s(rc, NAME_CATEGORY)), - LOC(default_locale, "stat_tribe_p"), pcomp(s->factionrace[i], - o->factionrace[i])); - } - } - } + summarize_players(s, F); if (full) { fprintf(F, "\n"); { struct language *plang = s->languages; while (plang != NULL) { - struct language *olang = o->languages; - int nold = 0; - while (olang && olang->locale != plang->locale) - olang = olang->next; - if (olang) - nold = olang->number; - fprintf(F, "Sprache %12s: %s\n", locale_name(plang->locale), - rcomp(plang->number, nold)); + fprintf(F, "Sprache %2s: %8d\n", locale_name(plang->locale), + plang->number); plang = plang->next; } } } fprintf(F, "\n"); - if (full) { - for (i = 0; i < MAXRACES; i++) { - if (s->poprace[i]) { - const race *rc = get_race(i); - fprintf(F, "%20s: %s\n", LOC(default_locale, rc_name_s(rc, NAME_PLURAL)), - rcomp(s->poprace[i], o->poprace[i])); - } - } - } - else { - for (i = 0; i < MAXRACES; i++) { - if (i != RC_TEMPLATE && i != RC_CLONE && s->poprace[i]) { - const race *rc = get_race(i); - if (playerrace(rc)) { - fprintf(F, "%20s: %s\n", LOC(default_locale, rc_name_s(rc, NAME_PLURAL)), - rcomp(s->poprace[i], o->poprace[i])); - } - } - } - } + summarize_races(s, F, full); if (full) { - fprintf(F, "\nWaffen: %s\n", pcomp(s->waffen, o->waffen)); - fprintf(F, "Ruestungen: %s\n", - pcomp(s->ruestungen, o->ruestungen)); - fprintf(F, "ungezaehmte Pferde: %s\n", pcomp(s->pferde, o->pferde)); - fprintf(F, "gezaehmte Pferde: %s\n", - pcomp(s->spielerpferde, o->spielerpferde)); - fprintf(F, "Schiffe: %s\n", pcomp(s->schiffe, o->schiffe)); - fprintf(F, "Gebaeude: %s\n", pcomp(s->gebaeude, o->gebaeude)); - - fprintf(F, "\nBauernpopulation: %s\n", pcomp(s->peasants, o->peasants)); - - fprintf(F, "Population gesamt: %d\n\n", s->playerpop + s->peasants); - - fprintf(F, "Reichtum Spieler: %s Silber\n", - pcomp(s->playermoney, o->playermoney)); - fprintf(F, "Reichtum Bauern: %s Silber\n", - pcomp(s->peasantmoney, o->peasantmoney)); - fprintf(F, "Reichtum gesamt: %s Silber\n\n", - pcomp(s->playermoney + s->peasantmoney, - o->playermoney + o->peasantmoney)); + fprintf(F, "\nWaffen: %8d\n", s->waffen); + fprintf(F, "Ruestungen: %8d\n", s->ruestungen); + fprintf(F, "ungezaehmte Pferde: %8d\n", s->pferde); + fprintf(F, "gezaehmte Pferde: %8d\n", s->spielerpferde); + fprintf(F, "Schiffe: %8d\n", s->schiffe); + fprintf(F, "Gebaeude: %8d\n", s->gebaeude); + + fprintf(F, "\nBauernpopulation: %8d\n", s->peasants); + + fprintf(F, "Population gesamt: %8d\n\n", s->playerpop + s->peasants); + + fprintf(F, "Reichtum Spieler: %12lld Silber\n", s->playermoney); + fprintf(F, "Reichtum Bauern: %12lld Silber\n", s->peasantmoney); + fprintf(F, "Reichtum gesamt: %12lld Silber\n\n", + s->playermoney + s->peasantmoney); } - fprintf(F, "\n\n"); + fprintf(F, "\n"); newplayers = update_nmrs(); if (nmrs) { + int i; for (i = 0; i <= timeout; ++i) { if (i == timeout) { - fprintf(F, "+ NMR:\t\t %d\n", nmrs[i]); + fprintf(F, "+ NMR: %3d\n", nmrs[i]); } else { - fprintf(F, "%d NMR:\t\t %d\n", i, nmrs[i]); + fprintf(F, "%d NMR: %3d\n", i, nmrs[i]); } } } if (age) { if (age[2] != 0) { - fprintf(F, "Erstabgaben:\t %d%%\n", 100 - (dropouts[0] * 100 / age[2])); + fprintf(F, "Erstabgaben: %3d%%\n", 100 - (dropouts[0] * 100 / age[2])); } if (age[3] != 0) { - fprintf(F, "Zweitabgaben:\t %d%%\n", 100 - (dropouts[1] * 100 / age[3])); + fprintf(F, "Zweitabgaben: %3d%%\n", 100 - (dropouts[1] * 100 / age[3])); } } - fprintf(F, "Neue Spieler:\t %d\n", newplayers); + fprintf(F, "Neue Spieler: %d\n", newplayers); if (full) { if (factions) { @@ -334,6 +346,7 @@ void report_summary(summary * s, summary * o, bool full) } if (timeout>0 && full) { + int i; fprintf(F, "\n\nFactions with NMRs:\n"); for (i = timeout; i > 0; --i) { for (f = factions; f; f = f->next) { diff --git a/src/summary.h b/src/summary.h index b12d74009..22832e4cb 100644 --- a/src/summary.h +++ b/src/summary.h @@ -19,7 +19,7 @@ extern "C" { struct summary; - void report_summary(struct summary *n, struct summary *o, bool full); + void report_summary(const struct summary *sum, bool full); struct summary *make_summary(void); void free_summary(struct summary *sum); int update_nmrs(void); diff --git a/src/summary.test.c b/src/summary.test.c index 93c4d4c84..5df4849c3 100644 --- a/src/summary.test.c +++ b/src/summary.test.c @@ -12,15 +12,15 @@ static void test_summary(CuTest * tc) { struct summary *sum; test_setup(); - test_create_faction(0); - test_create_faction(0); + test_create_faction(NULL); + test_create_faction(NULL); sum = make_summary(); - report_summary(sum, sum, true); + report_summary(sum, true); CuAssertIntEquals(tc, 0, remove("parteien.full")); CuAssertIntEquals(tc, 0, remove("datum")); CuAssertIntEquals(tc, 0, remove("turn")); free_summary(sum); - test_cleanup(); + test_teardown(); } CuSuite *get_summary_suite(void) diff --git a/src/teleport.c b/src/teleport.c index c529d5129..439b44955 100644 --- a/src/teleport.c +++ b/src/teleport.c @@ -141,24 +141,46 @@ region_list *all_in_range(const region * r, int n, return rlist; } +#define MAX_BRAIN_SIZE 100 + void spawn_braineaters(float chance) { + const race * rc_brain = get_race(RC_HIRNTOETER); region *r; - faction *f0 = get_monsters(); + faction *f = get_monsters(); int next = rng_int() % (int)(chance * 100); - if (f0 == NULL) + if (f == NULL || rc_brain == NULL) { return; + } for (r = regions; r; r = r->next) { + unit *u, *ub = NULL; if (!is_astral(r) || fval(r->terrain, FORBIDDEN_REGION)) continue; + for (u = r->units; u; u = u->next) { + if (u->_race == rc_brain) { + if (!ub) { + ub = u; + } + else { + int n = u->number + ub->number; + if (n <= MAX_BRAIN_SIZE) { + scale_number(ub, n); + u->number = 0; + } + else { + ub = u; + } + } + } + } + /* Neues Monster ? */ if (next-- == 0) { - unit *u = - create_unit(r, f0, 1 + rng_int() % 10 + rng_int() % 10, - get_race(RC_HIRNTOETER), 0, NULL, NULL); + u = create_unit(r, f, 1 + rng_int() % 10 + rng_int() % 10, + rc_brain, 0, NULL, NULL); equip_unit(u, get_equipment("seed_braineater")); next = rng_int() % (int)(chance * 100); diff --git a/src/test_eressea.c b/src/test_eressea.c index 38c5cf026..c299fc09c 100644 --- a/src/test_eressea.c +++ b/src/test_eressea.c @@ -1,11 +1,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #pragma warning(disable: 4210) @@ -34,7 +36,7 @@ static void add_suite(CuSuite *(*csuite)(void), const char *name, int argc, char } if (s) { s->next = suites; - s->name = strdup(name); + s->name = str_strdup(name); s->csuite = csuite(); suites = s; } @@ -76,7 +78,6 @@ int RunAllTests(int argc, char *argv[]) ADD_SUITE(config); ADD_SUITE(attrib); ADD_SUITE(base36); - ADD_SUITE(bsdstring); ADD_SUITE(functions); ADD_SUITE(gamedata); ADD_SUITE(language); @@ -91,31 +92,34 @@ int RunAllTests(int argc, char *argv[]) /* items */ ADD_SUITE(xerewards); /* kernel */ + ADD_SUITE(academy); + ADD_SUITE(alchemy); ADD_SUITE(alliance); + ADD_SUITE(ally); + ADD_SUITE(building); ADD_SUITE(command); - ADD_SUITE(plane); - ADD_SUITE(unit); + ADD_SUITE(db); ADD_SUITE(faction); ADD_SUITE(group); ADD_SUITE(build); - ADD_SUITE(pool); ADD_SUITE(curse); ADD_SUITE(equipment); ADD_SUITE(familiar); ADD_SUITE(item); ADD_SUITE(magic); - ADD_SUITE(alchemy); + ADD_SUITE(magicresistance); + ADD_SUITE(messages); + ADD_SUITE(plane); + ADD_SUITE(pool); ADD_SUITE(reports); ADD_SUITE(region); ADD_SUITE(save); ADD_SUITE(ship); + ADD_SUITE(skills); ADD_SUITE(spellbook); - ADD_SUITE(building); ADD_SUITE(spell); ADD_SUITE(spells); - ADD_SUITE(magicresistance); - ADD_SUITE(ally); - ADD_SUITE(messages); + ADD_SUITE(unit); /* gamecode */ ADD_SUITE(battle); ADD_SUITE(calendar); @@ -132,6 +136,7 @@ int RunAllTests(int argc, char *argv[]) ADD_SUITE(monsters); ADD_SUITE(move); ADD_SUITE(names); + ADD_SUITE(orderdb); ADD_SUITE(orderfile); ADD_SUITE(otherfaction); ADD_SUITE(piracy); diff --git a/src/tests.c b/src/tests.c index 770d2853c..18ecdef34 100644 --- a/src/tests.c +++ b/src/tests.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -22,8 +23,6 @@ #include #include #include -#include -#include #include #include #include @@ -44,6 +43,7 @@ struct race *test_create_race(const char *name) rc->maintenance = 10; rc->hitpoints = 20; rc->maxaura = 100; + rc->flags |= RCF_WALK; rc->ec_flags |= ECF_GETITEM; rc->battle_flags = BF_EQUIPMENT; return rc; @@ -62,6 +62,7 @@ struct region *test_create_region(int x, int y, const terrain_type *terrain) else { terraform_region(r, terrain); } + r->flags &= ~RF_MALLORN; rsettrees(r, 0, 0); rsettrees(r, 1, 0); rsettrees(r, 2, 0); @@ -120,12 +121,13 @@ struct locale * test_create_locale(void) { locale_setstring(loc, alliance_kwd[i], alliance_kwd[i]); } for (i = 0; i != MAXDIRECTIONS; ++i) { + locale_setstring(loc, shortdirections[i], shortdirections[i] + 4); locale_setstring(loc, directions[i], directions[i]); init_direction(loc, i, directions[i]); - init_direction(loc, i, coasts[i]+7); + init_direction(loc, i, coasts[i] + 7); } for (i = 0; i <= ST_FLEE; ++i) { - locale_setstring(loc, combatstatus[i], combatstatus[i]+7); + locale_setstring(loc, combatstatus[i], combatstatus[i] + 7); } for (i = 0; i != MAXKEYWORDS; ++i) { locale_setstring(loc, mkname("keyword", keywords[i]), keywords[i]); @@ -176,7 +178,7 @@ void test_log_stderr(int flags) { static struct log_t *stderrlog; if (flags) { if (stderrlog) { - log_error("stderr logging is still active. did you call test_cleanup?"); + log_error("stderr logging is still active. did you call test_teardown?"); log_destroy(stderrlog); } stderrlog = log_to_file(flags, stderr); @@ -186,7 +188,7 @@ void test_log_stderr(int flags) { log_destroy(stderrlog); } else { - log_warning("stderr logging is inactive. did you call test_cleanup twice?"); + log_warning("stderr logging is inactive. did you call test_teardown twice?"); } stderrlog = 0; } @@ -229,6 +231,10 @@ static void test_reset(void) { } random_source_reset(); + mt_register(mt_new_va("changepasswd", "value:string", NULL)); + mt_register(mt_new_va("starvation", "unit:unit", "region:region", "dead:int", "live:int", NULL)); + mt_register(mt_new_va("malnourish", "unit:unit", "region:region", NULL)); + if (errno) { int error = errno; errno = 0; @@ -236,9 +242,15 @@ static void test_reset(void) { } } +void test_inject_messagetypes(void) +{ + message_handle_missing(MESSAGE_MISSING_REPLACE); +} + void test_setup_test(CuTest *tc, const char *file, int line) { test_log_stderr(LOG_CPERROR); test_reset(); + message_handle_missing(MESSAGE_MISSING_ERROR); if (tc) { log_debug("start test: %s", tc->name); } @@ -247,7 +259,7 @@ void test_setup_test(CuTest *tc, const char *file, int line) { } } -void test_cleanup(void) +void test_teardown(void) { test_reset(); test_log_stderr(0); @@ -388,6 +400,12 @@ void test_translate_param(const struct locale *lang, param_t param, const char * add_translation(cb, text, param); } +item_type *test_create_silver(void) { + item_type * itype; + itype = test_create_itemtype("money"); + itype->weight = 1; + return itype; +} item_type *test_create_horse(void) { item_type * itype; @@ -446,10 +464,10 @@ void test_create_world(void) test_create_itemtype("iron"); test_create_itemtype("stone"); - t_plain = test_create_terrain("plain", LAND_REGION | FOREST_REGION | WALK_INTO | CAVALRY_REGION | FLY_INTO); + t_plain = test_create_terrain("plain", LAND_REGION | FOREST_REGION | WALK_INTO | CAVALRY_REGION | FLY_INTO); t_plain->size = 1000; t_plain->max_road = 100; - t_ocean = test_create_terrain("ocean", SEA_REGION | SWIM_INTO | FLY_INTO); + t_ocean = test_create_terrain("ocean", SEA_REGION | SWIM_INTO | FLY_INTO); t_ocean->size = 0; island[0] = test_create_region(0, 0, t_plain); @@ -545,20 +563,20 @@ void assert_message(CuTest * tc, message *msg, char *name, int numpar) { void assert_pointer_parameter(CuTest * tc, message *msg, int index, void *arg) { const message_type *mtype = (msg)->type; - CuAssertIntEquals((tc), VAR_VOIDPTR, mtype->types[(index)]->vtype);CuAssertPtrEquals((tc), (arg), msg->parameters[(index)].v); + CuAssertIntEquals((tc), VAR_VOIDPTR, mtype->types[(index)]->vtype); CuAssertPtrEquals((tc), (arg), msg->parameters[(index)].v); } void assert_int_parameter(CuTest * tc, message *msg, int index, int arg) { const message_type *mtype = (msg)->type; - CuAssertIntEquals((tc), VAR_INT, mtype->types[(index)]->vtype);CuAssertIntEquals((tc), (arg), msg->parameters[(index)].i); + CuAssertIntEquals((tc), VAR_INT, mtype->types[(index)]->vtype); CuAssertIntEquals((tc), (arg), msg->parameters[(index)].i); } void assert_string_parameter(CuTest * tc, message *msg, int index, const char *arg) { const message_type *mtype = (msg)->type; - CuAssertIntEquals((tc), VAR_VOIDPTR, mtype->types[(index)]->vtype);CuAssertStrEquals((tc), (arg), msg->parameters[(index)].v); + CuAssertIntEquals((tc), VAR_VOIDPTR, mtype->types[(index)]->vtype); CuAssertStrEquals((tc), (arg), msg->parameters[(index)].v); } -void disabled_test(void *suite, void (*test)(CuTest *), const char *name) { +void disabled_test(void *suite, void(*test)(CuTest *), const char *name) { (void)test; fprintf(stderr, "%s: SKIP\n", name); } diff --git a/src/tests.h b/src/tests.h index 669318d99..54764fd94 100644 --- a/src/tests.h +++ b/src/tests.h @@ -35,7 +35,7 @@ extern "C" { #define test_setup() test_setup_test(NULL, __FILE__, __LINE__) #define test_setup_ex(tc) test_setup_test(tc, __FILE__, __LINE__) - void test_cleanup(void); + void test_teardown(void); void test_log_stderr(int on); struct log_t * test_log_start(int flags, struct strlist **slist); void test_log_stop(struct log_t *log, struct strlist *slist); @@ -50,6 +50,7 @@ extern "C" { struct unit *test_create_unit(struct faction *f, struct region *r); void test_create_world(void); struct item_type * test_create_horse(void); + struct item_type * test_create_silver(void); struct building * test_create_building(struct region * r, const struct building_type * btype); struct ship * test_create_ship(struct region * r, const struct ship_type * stype); struct item_type * test_create_itemtype(const char * name); @@ -58,7 +59,6 @@ extern "C" { void test_create_castorder(struct castorder *co, struct unit *u, int level, float force, int range, struct spellparameter *par); struct spell * test_create_spell(void); - int RunAllTests(void); void test_translate_param(const struct locale *lang, param_t param, const char *text); const char * test_get_messagetype(const struct message *msg); struct message * test_find_messagetype_ex(struct message_list *msgs, const char *name, struct message *prev); @@ -73,6 +73,7 @@ extern "C" { void assert_string_parameter(struct CuTest * tc, struct message *msg, int index, const char *arg); void disabled_test(void *suite, void (*)(struct CuTest *), const char *name); + void test_inject_messagetypes(void); #define DISABLE_TEST(SUITE, TEST) disabled_test(SUITE, TEST, #TEST) diff --git a/src/tests.test.c b/src/tests.test.c index b2a90526d..067772262 100644 --- a/src/tests.test.c +++ b/src/tests.test.c @@ -32,7 +32,7 @@ static void test_resources(CuTest *tc) { CuAssertPtrEquals(tc, 0, rt_find("peasant")); rtype = rt_get_or_create("stone"); CuAssertPtrEquals(tc, (void *)rtype, (void *)get_resourcetype(R_STONE)); - test_cleanup(); + test_teardown(); } CuSuite *get_tests_suite(void) diff --git a/src/travelthru.c b/src/travelthru.c index 73aa97757..835d05024 100644 --- a/src/travelthru.c +++ b/src/travelthru.c @@ -28,7 +28,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include -#include #include #include diff --git a/src/travelthru.test.c b/src/travelthru.test.c index 09d807674..8a38891b1 100644 --- a/src/travelthru.test.c +++ b/src/travelthru.test.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "travelthru.h" #include "reports.h" @@ -28,14 +29,13 @@ static void setup_travelthru(travel_fixture *fix, int nunits) { region *r; faction *f; - test_cleanup(); - r = test_create_region(0, 0, 0); + r = test_create_region(0, 0, NULL); while (r->attribs) { a_remove(&r->attribs, r->attribs); } - f = test_create_faction(0); + f = test_create_faction(NULL); while (nunits--) { - unit *u = test_create_unit(f, test_create_region(1, 0, 0)); + unit *u = test_create_unit(f, test_create_region(1, 0, NULL)); travelthru_add(r, u); } fix->r = r; @@ -44,6 +44,8 @@ static void setup_travelthru(travel_fixture *fix, int nunits) { static void test_travelthru_count(CuTest *tc) { travel_fixture fix; + + test_setup(); setup_travelthru(&fix, 0); CuAssertIntEquals(tc, 0, count_travelthru(fix.r, fix.f)); @@ -53,13 +55,14 @@ static void test_travelthru_count(CuTest *tc) { setup_travelthru(&fix, 2); CuAssertIntEquals(tc, 2, count_travelthru(fix.r, fix.f)); - test_cleanup(); + test_teardown(); } static void test_travelthru_map(CuTest *tc) { int n = 0; travel_fixture fix; + test_setup(); setup_travelthru(&fix, 0); travelthru_map(fix.r, count_travelers, &n); CuAssertIntEquals(tc, 0, n); @@ -68,7 +71,7 @@ static void test_travelthru_map(CuTest *tc) { travelthru_map(fix.r, count_travelers, &n); CuAssertIntEquals(tc, 1, n); - test_cleanup(); + test_teardown(); } CuSuite *get_travelthru_suite(void) diff --git a/src/triggers/changefaction.c b/src/triggers/changefaction.c index 6a2700afa..f34cb98bd 100644 --- a/src/triggers/changefaction.c +++ b/src/triggers/changefaction.c @@ -25,11 +25,12 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* util includes */ #include +#include #include #include #include +#include #include -#include #include diff --git a/src/triggers/changerace.c b/src/triggers/changerace.c index 1a065fce2..5ab56b346 100644 --- a/src/triggers/changerace.c +++ b/src/triggers/changerace.c @@ -25,11 +25,12 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* util includes */ #include +#include #include #include #include +#include #include -#include #include diff --git a/src/triggers/clonedied.c b/src/triggers/clonedied.c index edcf756f9..62c4c3343 100644 --- a/src/triggers/clonedied.c +++ b/src/triggers/clonedied.c @@ -27,11 +27,12 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* util includes */ #include +#include #include #include #include +#include #include -#include #include diff --git a/src/triggers/createcurse.c b/src/triggers/createcurse.c index 2551f7fb5..bd7422587 100644 --- a/src/triggers/createcurse.c +++ b/src/triggers/createcurse.c @@ -25,11 +25,12 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* util includes */ #include +#include #include #include #include +#include #include -#include #include diff --git a/src/triggers/createunit.c b/src/triggers/createunit.c index 951887860..f152d3766 100644 --- a/src/triggers/createunit.c +++ b/src/triggers/createunit.c @@ -31,6 +31,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include #include #include diff --git a/src/triggers/gate.c b/src/triggers/gate.c index a66e0365e..d3fa1a1a8 100644 --- a/src/triggers/gate.c +++ b/src/triggers/gate.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include diff --git a/src/triggers/giveitem.c b/src/triggers/giveitem.c index 0442d9295..08e4f0147 100644 --- a/src/triggers/giveitem.c +++ b/src/triggers/giveitem.c @@ -29,6 +29,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include #include #include diff --git a/src/triggers/killunit.c b/src/triggers/killunit.c index 230efa7dc..bca630177 100644 --- a/src/triggers/killunit.c +++ b/src/triggers/killunit.c @@ -28,6 +28,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include #include #include diff --git a/src/triggers/shock.c b/src/triggers/shock.c index ca4ad67df..7eae6f31a 100644 --- a/src/triggers/shock.c +++ b/src/triggers/shock.c @@ -19,7 +19,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include "shock.h" -#include "magic.h" +#include /* kernel includes */ #include @@ -34,6 +34,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include #include #include diff --git a/src/triggers/shock.test.c b/src/triggers/shock.test.c index 058dfaae3..314c877df 100644 --- a/src/triggers/shock.test.c +++ b/src/triggers/shock.test.c @@ -4,17 +4,24 @@ #include #include #include + #include +#include #include #include +static void shock_setup(void) { + mt_register(mt_new_va("shock", "mage:unit", "reason:string", NULL)); +} + static void test_shock(CuTest *tc) { unit *u; trigger *tt; test_setup(); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + shock_setup(); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); create_mage(u, M_GRAY); set_level(u, SK_MAGIC, 5); set_spellpoints(u, 10); @@ -26,7 +33,7 @@ static void test_shock(CuTest *tc) { CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "shock")); t_free(tt); free(tt); - test_cleanup(); + test_teardown(); } static void test_shock_low(CuTest *tc) { @@ -34,7 +41,8 @@ static void test_shock_low(CuTest *tc) { trigger *tt; test_setup(); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + shock_setup(); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); create_mage(u, M_GRAY); set_level(u, SK_MAGIC, 5); set_spellpoints(u, 1); @@ -45,7 +53,7 @@ static void test_shock_low(CuTest *tc) { CuAssertIntEquals(tc, 1, get_spellpoints(u)); t_free(tt); free(tt); - test_cleanup(); + test_teardown(); } CuSuite *get_shock_suite(void) diff --git a/src/triggers/timeout.c b/src/triggers/timeout.c index 43bb061c8..5179bd832 100644 --- a/src/triggers/timeout.c +++ b/src/triggers/timeout.c @@ -24,6 +24,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include #include diff --git a/src/upkeep.c b/src/upkeep.c index d7626084d..6748d620c 100644 --- a/src/upkeep.c +++ b/src/upkeep.c @@ -1,4 +1,6 @@ +#ifdef _MSC_VER #include +#endif #include "upkeep.h" #include @@ -42,7 +44,7 @@ static void help_feed(unit * donor, unit * u, int *need_p) { int need = *need_p; int give = get_money(donor) - lifestyle(donor); - give = MIN(need, give); + if (give > need) give = need; if (give > 0) { change_money(donor, -give); @@ -109,16 +111,27 @@ void get_food(region * r) plane *pl = rplane(r); unit *u; int peasantfood = rpeasants(r) * 10; - int food_rules = config_get_int("rules.food.flags", 0); - static const race *rc_demon; - static int rc_cache; - + static const race *rc_demon, *rc_insect; + static int rc_cache, config_cache; + static int food_rules; + static bool insect_hunger; + static bool demon_hunger; + bool is_cold; + if (rc_changed(&rc_cache)) { rc_demon = get_race(RC_DAEMON); + rc_insect = get_race(RC_INSECT); + } + if (config_changed(&config_cache)) { + food_rules = config_get_int("rules.food.flags", 0); + insect_hunger = config_get_int("hunger.insect.cold", 1) != 0; + demon_hunger = config_get_int("hunger.demon.peasant_tolerance", 0) == 0; } if (food_rules & FOOD_IS_FREE) { return; } + is_cold = insect_hunger && r_insectstalled(r); + /* 1. Versorgung von eigenen Einheiten. Das vorhandene Silber * wird zun�chst so auf die Einheiten aufgeteilt, dass idealerweise * jede Einheit genug Silber f�r ihren Unterhalt hat. */ @@ -156,7 +169,7 @@ void get_food(region * r) * food from the peasants - should not be used with WORK */ if (owner != NULL && (get_alliance(owner, u->faction) & HELP_MONEY)) { int rm = rmoney(r); - int use = MIN(rm, need); + int use = (rm < need) ? rm : need; rsetmoney(r, rm - use); need -= use; } @@ -169,7 +182,7 @@ void get_food(region * r) for (v = r->units; need && v; v = v->next) { if (v->faction == u->faction) { int give = get_money(v) - lifestyle(v); - give = MIN(need, give); + if (give > need) give = need; if (give > 0) { change_money(v, -give); change_money(u, give); @@ -183,11 +196,11 @@ void get_food(region * r) /* 2. Versorgung durch Fremde. Das Silber alliierter Einheiten wird * entsprechend verteilt. */ for (u = r->units; u; u = u->next) { - int need = lifestyle(u); + int need; faction *f = u->faction; assert(u->hp > 0); - need -= MAX(0, get_money(u)); + need = lifestyle(u) - get_money(u); if (need > 0) { unit *v; @@ -227,30 +240,27 @@ void get_food(region * r) * bei fehlenden Bauern den D�mon hungern lassen */ for (u = r->units; u; u = u->next) { - if (u_race(u) == rc_demon) { + const race * rc = u_race(u); + if (rc == rc_demon) { int hungry = u->number; /* use peasantblood before eating the peasants themselves */ - const struct potion_type *pt_blood = 0; - const resource_type *rt_blood = rt_find("peasantblood"); - if (rt_blood) { - pt_blood = rt_blood->ptype; - } - if (pt_blood) { + const struct item_type *it_blood = it_find("peasantblood"); + if (it_blood) { /* always start with the unit itself, then the first known unit that may have some blood */ unit *donor = u; while (donor != NULL && hungry > 0) { - int blut = get_effect(donor, pt_blood); - blut = MIN(blut, hungry); - if (blut) { - change_effect(donor, pt_blood, -blut); + int blut = get_effect(donor, it_blood); + if (hungry < blut) blut = hungry; + if (blut > 0) { + change_effect(donor, it_blood, -blut); hungry -= blut; } if (donor == u) donor = r->units; while (donor != NULL) { if (u_race(donor) == rc_demon && donor != u) { - if (get_effect(donor, pt_blood)) { + if (get_effect(donor, it_blood)) { /* if he's in our faction, drain him: */ if (donor->faction == u->faction) break; @@ -271,7 +281,6 @@ void get_food(region * r) peasantfood = 0; } if (hungry > 0) { - bool demon_hunger = config_get_int("hunger.demons.peasant_tolerance", 0) == 0; if (demon_hunger) { /* demons who don't feed are hungry */ if (hunger(hungry, u)) @@ -284,12 +293,20 @@ void get_food(region * r) } } } + else if (is_cold && rc == rc_insect) { + /* insects in glaciers get hunger damage */ + if (hunger(u->number, u)) { + fset(u, UFL_HUNGER); + } + } } rsetpeasants(r, peasantfood / 10); /* 3. Von den �berlebenden das Geld abziehen: */ for (u = r->units; u; u = u->next) { - int need = MIN(get_money(u), lifestyle(u)); + int m = get_money(u); + int need = lifestyle(u); + if (need > m) need = m; change_money(u, -need); } } diff --git a/src/upkeep.test.c b/src/upkeep.test.c index bc53d5bbc..f2fedc89b 100644 --- a/src/upkeep.test.c +++ b/src/upkeep.test.c @@ -39,7 +39,7 @@ void test_upkeep_default(CuTest * tc) CuAssertIntEquals(tc, 0, fval(u1, UFL_HUNGER)); CuAssertIntEquals(tc, UFL_HUNGER, fval(u2, UFL_HUNGER)); - test_cleanup(); + test_teardown(); } void test_upkeep_hunger_damage(CuTest * tc) @@ -65,7 +65,7 @@ void test_upkeep_hunger_damage(CuTest * tc) /* since u1 and u2 are not allied, u1 should not help u2 with upkeep */ CuAssertTrue(tc, u1->hp < 100); - test_cleanup(); + test_teardown(); } void test_upkeep_from_pool(CuTest * tc) @@ -97,7 +97,7 @@ void test_upkeep_from_pool(CuTest * tc) CuAssertIntEquals(tc, 0, fval(u1, UFL_HUNGER)); CuAssertIntEquals(tc, UFL_HUNGER, fval(u2, UFL_HUNGER)); - test_cleanup(); + test_teardown(); } @@ -133,7 +133,7 @@ void test_upkeep_from_friend(CuTest * tc) CuAssertIntEquals(tc, 0, fval(u1, UFL_HUNGER)); CuAssertIntEquals(tc, UFL_HUNGER, fval(u2, UFL_HUNGER)); - test_cleanup(); + test_teardown(); } void test_upkeep_free(CuTest * tc) @@ -156,7 +156,7 @@ void test_upkeep_free(CuTest * tc) CuAssertIntEquals(tc, 0, i_get(u->items, i_silver)); CuAssertIntEquals(tc, 0, fval(u, UFL_HUNGER)); - test_cleanup(); + test_teardown(); } CuSuite *get_upkeep_suite(void) diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index 91ed118ae..dce14684a 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -3,7 +3,7 @@ project(util C) SET(_TEST_FILES attrib.test.c base36.test.c -bsdstring.test.c +# bsdstring.test.c # crmessage.test.c # dice.test.c # event.test.c @@ -22,7 +22,6 @@ password.test.c # resolve.test.c rng.test.c strings.test.c -bsdstring.test.c functions.test.c log.test.c # translation.test.c @@ -51,6 +50,7 @@ mt19937ar.c nrmessage.c parser.c password.c +path.c rand.c resolve.c strings.c @@ -60,6 +60,7 @@ unicode.c variant.c xml.c ) + FOREACH(_FILE ${_FILES}) LIST(APPEND _SOURCES ${PROJECT_NAME}/${_FILE}) ENDFOREACH(_FILE) diff --git a/src/util/attrib.c b/src/util/attrib.c index b6214fdd6..8a90f3bca 100644 --- a/src/util/attrib.c +++ b/src/util/attrib.c @@ -19,10 +19,11 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include "attrib.h" +#include "gamedata.h" #include "log.h" #include "storage.h" +#include "strings.h" -#include #include #include @@ -119,12 +120,17 @@ int a_readstring(attrib * a, void *owner, struct gamedata *data) do { e = READ_STR(data->store, buf, sizeof(buf)); if (result) { - result = realloc(result, len + DISPLAYSIZE - 1); + char *tmp = realloc(result, len + DISPLAYSIZE - 1); + if (!tmp) { + free(result); + abort(); + } + result = tmp; strcpy(result + len, buf); len += DISPLAYSIZE - 1; } else { - result = strdup(buf); + result = str_strdup(buf); } } while (e == ENOMEM); a->data.v = result; @@ -532,5 +538,5 @@ void a_write_orig(struct storage *store, const attrib * attribs, const void *own void attrib_done(void) { cb_clear(&cb_deprecated); - memset(at_hash, 0, sizeof at_hash); + memset(at_hash, 0, sizeof(at_hash[0]) * MAXATHASH); } diff --git a/src/util/attrib.test.c b/src/util/attrib.test.c index c59b8ae24..34427385f 100644 --- a/src/util/attrib.test.c +++ b/src/util/attrib.test.c @@ -2,6 +2,7 @@ #include "attrib.h" #include +#include #include #include @@ -119,7 +120,7 @@ static void test_attrib_rwstring(CuTest *tc) { attrib a = { 0 }; test_setup(); - a.data.v = strdup("Hello World"); + a.data.v = str_strdup("Hello World"); mstream_init(&data.strm); gamedata_init(&data, &store, RELEASE_VERSION); a_writestring(&a, NULL, &store); @@ -130,7 +131,7 @@ static void test_attrib_rwstring(CuTest *tc) { a_finalizestring(&a); mstream_done(&data.strm); gamedata_done(&data); - test_cleanup(); + test_teardown(); } static void test_attrib_rwint(CuTest *tc) { @@ -149,7 +150,7 @@ static void test_attrib_rwint(CuTest *tc) { CuAssertIntEquals(tc, 42, a.data.i); mstream_done(&data.strm); gamedata_done(&data); - test_cleanup(); + test_teardown(); } static void test_attrib_rwchars(CuTest *tc) { @@ -170,7 +171,7 @@ static void test_attrib_rwchars(CuTest *tc) { CuAssertIntEquals(tc, 42, a.data.ca[3]); mstream_done(&data.strm); gamedata_done(&data); - test_cleanup(); + test_teardown(); } static void test_attrib_rwshorts(CuTest *tc) { @@ -191,7 +192,7 @@ static void test_attrib_rwshorts(CuTest *tc) { CuAssertIntEquals(tc, 42, a.data.sa[1]); mstream_done(&data.strm); gamedata_done(&data); - test_cleanup(); + test_teardown(); } CuSuite *get_attrib_suite(void) diff --git a/src/util/base36.c b/src/util/base36.c index 285e9760e..3ded21a54 100644 --- a/src/util/base36.c +++ b/src/util/base36.c @@ -52,18 +52,16 @@ int atoi36(const char *str) return i * sign; } -const char *itoab(int i, int base) +const char *itoab_r(int i, int base, char *s, size_t len) { - static char sstr[80]; - char *s, *dst; - static int index = 0; /* STATIC_XCALL: used across calls */ - int neg = 0; + char *dst; - s = sstr + (index * 20); - index = (index + 1) & 3; /* quick for % 4 */ - dst = s + 19; - (*dst--) = 0; + assert(len > 2); + dst = s + len - 2; + *dst = 0; if (i != 0) { + int neg = 0; + if (i < 0) { i = -i; neg = 1; @@ -100,6 +98,18 @@ const char *itoab(int i, int base) return dst; } +const char *itoab(int i, int base) +{ + static char sstr[80]; + char *s; + static int index = 0; /* STATIC_XCALL: used across calls */ + + s = sstr + (index * 20); + index = (index + 1) & 3; /* quick for % 4 */ + + return itoab_r(i, base, s, 20); +} + const char *itoa36(int i) { return itoab(i, 36); diff --git a/src/util/base36.h b/src/util/base36.h index 650538219..804952ab7 100644 --- a/src/util/base36.h +++ b/src/util/base36.h @@ -18,15 +18,19 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #ifndef H_UTIL_BASE36 #define H_UTIL_BASE36 + +#include + #ifdef __cplusplus extern "C" { #endif + const char *itoab_r(int i, int base, char *result, size_t len); + const char *itoab(int i, int base); + const char *itoa36(int i); + const char *itoa10(int i); extern int atoi36(const char *s); - extern const char *itoab(int i, int base); - extern const char *itoa36(int i); - extern const char *itoa10(int i); - extern int i10toi36(int i); + int i10toi36(int i); #ifdef __cplusplus } diff --git a/src/util/base36.test.c b/src/util/base36.test.c index b2e6fcbac..226fd86ab 100644 --- a/src/util/base36.test.c +++ b/src/util/base36.test.c @@ -1,3 +1,7 @@ +#ifdef _MSC_VER +#include +#endif + #include #include "base36.h" #include diff --git a/src/util/bsdstring.c b/src/util/bsdstring.c index 0f3d49801..19d6dee0d 100644 --- a/src/util/bsdstring.c +++ b/src/util/bsdstring.c @@ -1,13 +1,14 @@ +#ifdef _MSC_VER #include -#include +#endif #include #include #include -#include #include #include "bsdstring.h" #include "log.h" +#include "strings.h" int wrptr(char **ptr, size_t * size, int result) { @@ -35,37 +36,9 @@ int wrptr(char **ptr, size_t * size, int result) return ERANGE; } -#ifndef HAVE_STRLCPY -#define HAVE_STRLCPY -size_t strlcpy(char *dst, const char *src, size_t siz) -{ /* copied from OpenBSD source code */ - register char *d = dst; - register const char *s = src; - register size_t n = siz; - - assert(src && dst); - /* Copy as many bytes as will fit */ - if (n != 0 && --n != 0) { - do { - if ((*d++ = *s++) == 0) - break; - } while (--n != 0); - } - - /* Not enough room in dst, add NUL and traverse rest of src */ - if (n == 0) { - if (siz != 0) - *d = '\0'; /* NUL-terminate dst */ - while (*s++); - } - - return (s - src - 1); /* count does not include NUL */ -} -#endif - char * strlcpy_w(char *dst, const char *src, size_t *siz, const char *err, const char *file, int line) { - size_t bytes = strlcpy(dst, src, *siz); + size_t bytes = str_strlcpy(dst, src, *siz); char * buf = dst; assert(bytes <= INT_MAX); if (wrptr(&buf, siz, (int)bytes) != 0) { @@ -77,54 +50,3 @@ char * strlcpy_w(char *dst, const char *src, size_t *siz, const char *err, const } return buf; } - - - -#ifndef HAVE_STRLCAT -#define HAVE_STRLCAT -size_t strlcat(char *dst, const char *src, size_t siz) -{ - register char *d = dst; - register const char *s = src; - register size_t n = siz; - size_t dlen; - - /* Find the end of dst and adjust bytes left but don't go past end */ - while (*d != '\0' && n-- != 0) - d++; - dlen = d - dst; - n = siz - dlen; - - if (n == 0) - return (dlen + strlen(s)); - while (*s != '\0') { - if (n != 1) { - *d++ = *s; - n--; - } - s++; - } - *d = '\0'; - - return (dlen + (s - src)); /* count does not include NUL */ -} -#endif - -#ifndef HAVE_SLPRINTF -#define HAVE_SLPRINTF -size_t slprintf(char * dst, size_t size, const char * format, ...) -{ - va_list args; - int result; - - va_start(args, format); - result = vsnprintf(dst, size, format, args); - va_end(args); - if (result < 0 || result >= (int)size) { - dst[size - 1] = '\0'; - return size; - } - - return (size_t)result; -} -#endif diff --git a/src/util/bsdstring.h b/src/util/bsdstring.h index dad4d6281..56772180a 100644 --- a/src/util/bsdstring.h +++ b/src/util/bsdstring.h @@ -2,22 +2,12 @@ #define UTIL_BSDSTRING_H #include -int wrptr(char **ptr, size_t * size, int bytes); -#ifndef HAVE_STRLCPY -size_t strlcpy(char *dst, const char *src, size_t siz); -#endif +int wrptr(char **ptr, size_t * size, int bytes); char * strlcpy_w(char *dst, const char *src, size_t *siz, const char *err, const char *file, int line); -#ifndef HAVE_STRLCAT -size_t strlcat(char *dst, const char *src, size_t siz); -#endif - -#ifndef HAVE_SLPRINTF -size_t slprintf(char * dst, size_t size, const char * format, ...); -#endif +#define BUFFER_STRCAT(bufp, size, bytes) if (wrptr(&bufp, &size, bytes) != 0) log_warning("static buffer too small in %s:%d\n", __FILE__, __LINE__); -#define WARN_STATIC_BUFFER_EX(foo) log_warning("%s: static buffer too small in %s:%d\n", (foo), __FILE__, __LINE__) #define WARN_STATIC_BUFFER() log_warning("static buffer too small in %s:%d\n", __FILE__, __LINE__) #define INFO_STATIC_BUFFER() log_info("static buffer too small in %s:%d\n", __FILE__, __LINE__) #define STRLCPY(dst, src, siz) strlcpy_w((dst), (src), &(siz), 0, __FILE__, __LINE__) diff --git a/src/util/bsdstring.test.c b/src/util/bsdstring.test.c deleted file mode 100644 index d4276ef61..000000000 --- a/src/util/bsdstring.test.c +++ /dev/null @@ -1,70 +0,0 @@ -#include -#include "bsdstring.h" -#include -#include - -static void test_strlcat(CuTest * tc) -{ - char buffer[32]; - - memset(buffer, 0x7f, sizeof(buffer)); - - buffer[0] = '\0'; - CuAssertIntEquals(tc, 4, (int)strlcat(buffer, "herp", 4)); - CuAssertStrEquals(tc, "her", buffer); - - buffer[0] = '\0'; - CuAssertIntEquals(tc, 4, (int)strlcat(buffer, "herp", 8)); - CuAssertStrEquals(tc, "herp", buffer); - CuAssertIntEquals(tc, 0x7f, buffer[5]); - - CuAssertIntEquals(tc, 8, (int)strlcat(buffer, "derp", 8)); - CuAssertStrEquals(tc, "herpder", buffer); - CuAssertIntEquals(tc, 0x7f, buffer[8]); -} - -static void test_strlcpy(CuTest * tc) -{ - char buffer[32]; - - memset(buffer, 0x7f, sizeof(buffer)); - - CuAssertIntEquals(tc, 4, (int)strlcpy(buffer, "herp", 4)); - CuAssertStrEquals(tc, "her", buffer); - - CuAssertIntEquals(tc, 4, (int)strlcpy(buffer, "herp", 8)); /*-V666 */ - CuAssertStrEquals(tc, "herp", buffer); - CuAssertIntEquals(tc, 0x7f, buffer[5]); - - CuAssertIntEquals(tc, 8, (int)strlcpy(buffer, "herpderp", 8)); - CuAssertStrEquals(tc, "herpder", buffer); - CuAssertIntEquals(tc, 0x7f, buffer[8]); - errno = 0; -} - -static void test_slprintf(CuTest * tc) -{ - char buffer[32]; - - memset(buffer, 0x7f, sizeof(buffer)); - - CuAssertTrue(tc, slprintf(buffer, 4, "%s", "herpderp") > 3); - CuAssertStrEquals(tc, "her", buffer); - - CuAssertIntEquals(tc, 4, (int)slprintf(buffer, 8, "%s", "herp")); - CuAssertStrEquals(tc, "herp", buffer); - CuAssertIntEquals(tc, 0x7f, buffer[5]); - - CuAssertIntEquals(tc, 8, (int)slprintf(buffer, 8, "%s", "herpderp")); - CuAssertStrEquals(tc, "herpder", buffer); - CuAssertIntEquals(tc, 0x7f, buffer[8]); -} - -CuSuite *get_bsdstring_suite(void) -{ - CuSuite *suite = CuSuiteNew(); - SUITE_ADD_TEST(suite, test_strlcat); - SUITE_ADD_TEST(suite, test_strlcpy); - SUITE_ADD_TEST(suite, test_slprintf); - return suite; -} diff --git a/src/util/crmessage.c b/src/util/crmessage.c index dd400bf3d..3e3b05177 100644 --- a/src/util/crmessage.c +++ b/src/util/crmessage.c @@ -14,6 +14,7 @@ #include #include "crmessage.h" +#include "macros.h" #include "message.h" #include "strings.h" #include "log.h" diff --git a/src/util/event.c b/src/util/event.c index 78a6d6fbc..298f9d93e 100644 --- a/src/util/event.c +++ b/src/util/event.c @@ -23,7 +23,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "attrib.h" #include "gamedata.h" #include "log.h" -#include "storage.h" +#include "strings.h" + +#include /* libc includes */ #include @@ -153,7 +155,7 @@ static int read_handler(attrib * a, void *owner, gamedata *data) handler_info *hi = (handler_info *)a->data.v; READ_TOK(store, zText, sizeof(zText)); - hi->event = strdup(zText); + hi->event = str_strdup(zText); read_triggers(data, &hi->triggers); if (hi->triggers != NULL) { return AT_READ_OK; @@ -200,7 +202,7 @@ void add_trigger(struct attrib **ap, const char *eventname, struct trigger *t) if (a == NULL || a->type != &at_eventhandler) { a = a_add(ap, a_new(&at_eventhandler)); td = (handler_info *)a->data.v; - td->event = strdup(eventname); + td->event = str_strdup(eventname); } tp = &td->triggers; while (*tp) diff --git a/src/util/functions.test.c b/src/util/functions.test.c index ddd882821..32606b98f 100644 --- a/src/util/functions.test.c +++ b/src/util/functions.test.c @@ -1,3 +1,6 @@ +#ifdef _MSC_VER +#include +#endif #include #include #include diff --git a/src/util/goodies.c b/src/util/goodies.c index 0794240d5..fcfaa1013 100644 --- a/src/util/goodies.c +++ b/src/util/goodies.c @@ -109,17 +109,13 @@ static int spc_email_isvalid(const char *address) return (count >= 1); } -int set_email(char **pemail, const char *newmail) +int check_email(const char *newmail) { if (newmail && *newmail) { if (spc_email_isvalid(newmail) <= 0) return -1; - } - if (*pemail) - free(*pemail); - *pemail = 0; - if (newmail) { - *pemail = strdup(newmail); + } else { + return -1; } return 0; } diff --git a/src/util/goodies.h b/src/util/goodies.h index c619c4958..bb3a372f6 100644 --- a/src/util/goodies.h +++ b/src/util/goodies.h @@ -23,7 +23,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif - int set_email(char **pemail, const char *newmail); + int check_email(const char *newmail); int *intlist_init(void); int *intlist_add(int *i_p, int i); diff --git a/src/util/language.c b/src/util/language.c index b3cce61af..689ccfcd7 100644 --- a/src/util/language.c +++ b/src/util/language.c @@ -16,7 +16,10 @@ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. **/ +#ifdef _MSC_VER #include +#endif + #include "language.h" #include "log.h" @@ -45,9 +48,6 @@ typedef struct locale { struct locale_str *strings[SMAXHASH]; } locale; -extern locale *default_locale; -extern locale *locales; - locale *default_locale; locale *locales; @@ -59,7 +59,7 @@ unsigned int locale_index(const locale * lang) locale *get_locale(const char *name) { - unsigned int hkey = hashstring(name); + unsigned int hkey = str_hash(name); locale *l = locales; while (l && l->hashkey != hkey) l = l->next; @@ -71,7 +71,7 @@ static unsigned int nextlocaleindex = 0; locale *get_or_create_locale(const char *name) { locale *l; - unsigned int hkey = hashstring(name); + unsigned int hkey = str_hash(name); locale **lp = &locales; if (!locales) { @@ -86,7 +86,7 @@ locale *get_or_create_locale(const char *name) *lp = l = (locale *)calloc(sizeof(locale), 1); assert_alloc(l); l->hashkey = hkey; - l->name = strdup(name); + l->name = str_strdup(name); l->index = nextlocaleindex++; assert(nextlocaleindex <= MAXLOCALES); if (default_locale == NULL) default_locale = l; @@ -123,7 +123,7 @@ void make_locales(const char *str) const char *locale_getstring(const locale * lang, const char *key) { - unsigned int hkey = hashstring(key); + unsigned int hkey = str_hash(key); unsigned int id = hkey & (SMAXHASH - 1); const struct locale_str *find; @@ -153,7 +153,7 @@ const char *locale_string(const locale * lang, const char *key, bool warn) assert(key); if (key != NULL) { - unsigned int hkey = hashstring(key); + unsigned int hkey = str_hash(key); unsigned int id = hkey & (SMAXHASH - 1); struct locale_str *find; @@ -191,7 +191,7 @@ const char *locale_string(const locale * lang, const char *key, bool warn) void locale_setstring(locale * lang, const char *key, const char *value) { - unsigned int hkey = hashstring(key); + unsigned int hkey = str_hash(key); unsigned int id = hkey & (SMAXHASH - 1); struct locale_str *find; if (!lang) { @@ -209,15 +209,15 @@ void locale_setstring(locale * lang, const char *key, const char *value) find->nexthash = lang->strings[id]; lang->strings[id] = find; find->hashkey = hkey; - find->key = strdup(key); - find->str = strdup(value); + find->key = str_strdup(key); + find->str = str_strdup(value); } else { if (strcmp(find->str, value) != 0) { log_warning("multiple translations for key %s\n", key); } free(find->str); - find->str = strdup(value); + find->str = str_strdup(value); } } diff --git a/src/util/language.test.c b/src/util/language.test.c index 40a6775fa..077bd3ba2 100644 --- a/src/util/language.test.c +++ b/src/util/language.test.c @@ -13,7 +13,7 @@ static void test_language(CuTest *tc) default_locale = test_create_locale(); str = directions[1]; CuAssertStrEquals(tc, str, locale_getstring(default_locale, str)); - test_cleanup(); + test_teardown(); } static void test_make_locales(CuTest *tc) @@ -23,7 +23,7 @@ static void test_make_locales(CuTest *tc) CuAssertPtrNotNull(tc, get_locale("aa")); CuAssertPtrNotNull(tc, get_locale("bb")); CuAssertPtrNotNull(tc, get_locale("cc")); - test_cleanup(); + test_teardown(); } CuSuite *get_language_suite(void) diff --git a/src/util/lists.c b/src/util/lists.c index be3deeffd..81f9c9ab2 100644 --- a/src/util/lists.c +++ b/src/util/lists.c @@ -12,12 +12,16 @@ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +ACTION OF CONTRACT, NEGLIGENCE OR OTH19ER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. **/ +#ifdef _MSC_VER #include +#endif + #include "lists.h" +#include "strings.h" #include #include @@ -76,16 +80,6 @@ void translist(void *l1, void *l2, void *p) addlist(l2, p); } -void insertlist(void_list ** l, void_list * p) -{ - - /* insert entry p at the beginning of list l */ - - p->next = *l; - *l = p; - -} - void removelist(void *l, void *p) { @@ -127,7 +121,7 @@ void addstrlist(strlist ** SP, const char *s) { strlist *slist = malloc(sizeof(strlist)); slist->next = NULL; - slist->s = strdup(s); + slist->s = str_strdup(s); addlist(SP, slist); } diff --git a/src/util/lists.h b/src/util/lists.h index 8b9b093df..7fd0ca034 100644 --- a/src/util/lists.h +++ b/src/util/lists.h @@ -22,8 +22,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -#include - typedef struct strlist { struct strlist *next; char *s; @@ -33,14 +31,8 @@ extern "C" { void freestrlist(strlist * s); void addlist(void *l1, void *p1); void translist(void *l1, void *l2, void *p); -#ifndef MALLOCDBG void freelist(void *p1); void removelist(void *l, void *p); -#else -#define freelist(p) { while (p) { void * p2 = p->next; free(p); p = p2; } } -#define removelist(l,p) { choplist(l, p); free(p); } -#endif - unsigned int listlen(void *l); #ifdef __cplusplus diff --git a/src/util/log.c b/src/util/log.c index 24ddce757..51479cb4a 100644 --- a/src/util/log.c +++ b/src/util/log.c @@ -11,11 +11,13 @@ without prior permission by the authors of Eressea. */ #include #include "log.h" -#include "bsdstring.h" + #include "unicode.h" +#include "strings.h" #include #include +#include #include #include #include @@ -92,7 +94,7 @@ cp_convert(const char *format, unsigned char *buffer, size_t length, int codepag void log_rotate(const char *filename, int maxindex) { - char buffer[2][MAX_PATH]; + char buffer[2][PATH_MAX]; int dst = 1; assert(strlen(filename) < sizeof(buffer[0]) - 4); @@ -148,7 +150,7 @@ static int check_dupe(const char *format, int level) } dupes = 0; } - strlcpy(last_message, format, sizeof(last_message)); + str_strlcpy(last_message, format, sizeof(last_message)); last_type = level; return 0; } @@ -191,6 +193,16 @@ log_t *log_to_file(int flags, FILE *out) { return log_create(flags, out, log_stdio); } +#ifdef _MSC_VER +/* https://social.msdn.microsoft.com/Forums/vstudio/en-US/53a4fd75-9f97-48b2-aa63-2e2e5a15efa3/stdcversion-problem?forum=vclanguage */ +#define VA_COPY(c, a) va_copy(c, a) +#elif !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L +/* GNU only: https://www.gnu.org/software/libc/manual/html_node/Argument-Macros.html */ +#define VA_COPY(c, a) __va_copy(c, a) +#else +#define VA_COPY(c, a) va_copy(c, a) +#endif + static void log_write(int flags, const char *module, const char *format, va_list args) { log_t *lg; for (lg = loggers; lg; lg = lg->next) { @@ -202,8 +214,7 @@ static void log_write(int flags, const char *module, const char *format, va_list } if (dupe == 0) { va_list copy; - - va_copy(copy, args); + VA_COPY(copy, args); lg->log(lg->data, level, NULL, format, copy); va_end(copy); } @@ -211,13 +222,13 @@ static void log_write(int flags, const char *module, const char *format, va_list } } - void log_fatal(const char *format, ...) { va_list args; va_start(args, format); log_write(LOG_CPERROR, NULL, format, args); va_end(args); + abort(); } void log_error(const char *format, ...) /*-V524 */ diff --git a/src/util/log.test.c b/src/util/log.test.c index 1558ee3e3..86f13ea9c 100644 --- a/src/util/log.test.c +++ b/src/util/log.test.c @@ -1,7 +1,10 @@ +#ifdef _MSC_VER #include +#endif #include #include "log.h" +#include "macros.h" #include #include diff --git a/src/util/macros.h b/src/util/macros.h new file mode 100644 index 000000000..8ad17a86b --- /dev/null +++ b/src/util/macros.h @@ -0,0 +1,2 @@ +#define UNUSED_ARG(x) (void)(x) +#define TOLUA_CAST (char*) diff --git a/src/util/message.c b/src/util/message.c index c5285835e..a919f5f7d 100644 --- a/src/util/message.c +++ b/src/util/message.c @@ -11,7 +11,9 @@ */ +#ifdef _MSC_VER #include +#endif #include "message.h" #include "strings.h" @@ -60,8 +62,8 @@ arg_type *find_argtype(const char *name) message_type *mt_new(const char *name, const char *args[]) { - int i, nparameters = 0; - message_type *mtype = (message_type *)malloc(sizeof(message_type)); + int nparameters = 0; + message_type *mtype; assert(name != NULL); if (name == NULL) { @@ -72,8 +74,9 @@ message_type *mt_new(const char *name, const char *args[]) /* count the number of parameters */ while (args[nparameters]) ++nparameters; } + mtype = (message_type *)malloc(sizeof(message_type)); mtype->key = 0; - mtype->name = strdup(name); + mtype->name = str_strdup(name); mtype->nparameters = nparameters; if (nparameters > 0) { mtype->pnames = (char **)malloc(sizeof(char *) * nparameters); @@ -84,6 +87,8 @@ message_type *mt_new(const char *name, const char *args[]) mtype->types = NULL; } if (args != NULL) { + int i; + for (i = 0; args[i]; ++i) { const char *x = args[i]; const char *spos = strchr(x, ':'); @@ -122,6 +127,7 @@ message_type *mt_new_va(const char *name, ...) break; } va_end(marker); + args[i] = 0; return mt_new(name, args); } @@ -143,13 +149,14 @@ static void free_arg(const arg_type * atype, variant data) message *msg_create(const struct message_type *mtype, variant args[]) { int i; - message *msg = (message *)malloc(sizeof(message)); + message *msg; assert(mtype != NULL); if (mtype == NULL) { log_error("Trying to create message with type=0x0\n"); return NULL; } + msg = (message *)malloc(sizeof(message)); msg->type = mtype; msg->parameters = (variant *)(mtype->nparameters ? calloc(mtype->nparameters, sizeof(variant)) : NULL); msg->refcount = 1; @@ -188,7 +195,7 @@ void mt_clear(void) { const message_type *mt_find(const char *name) { - unsigned int hash = hashstring(name) % MT_MAXHASH; + unsigned int hash = str_hash(name) % MT_MAXHASH; selist *ql = messagetypes[hash]; int qi; @@ -207,6 +214,7 @@ static unsigned int mt_id(const message_type * mtype) size_t i = strlen(mtype->name); while (i > 0) { + /* TODO: why not use str_hash? */ key = (mtype->name[--i] + key * 37); } return key % 0x7FFFFFFF; @@ -214,7 +222,7 @@ static unsigned int mt_id(const message_type * mtype) const message_type *mt_register(message_type * type) { - unsigned int hash = hashstring(type->name) % MT_MAXHASH; + unsigned int hash = str_hash(type->name) % MT_MAXHASH; selist **qlp = messagetypes + hash; if (selist_set_insert(qlp, type, NULL)) { @@ -236,7 +244,7 @@ void msg_free(message * msg) void msg_release(struct message *msg) { - assert(msg->refcount > 0); + assert(msg && msg->refcount > 0); if (--msg->refcount > 0) return; msg_free(msg); @@ -244,7 +252,7 @@ void msg_release(struct message *msg) struct message *msg_addref(struct message *msg) { - assert(msg->refcount > 0); + assert(msg && msg->refcount > 0); ++msg->refcount; return msg; } diff --git a/src/util/message.test.c b/src/util/message.test.c index 7d5dc03e9..e86b3aa38 100644 --- a/src/util/message.test.c +++ b/src/util/message.test.c @@ -19,7 +19,7 @@ static void test_mt_new(CuTest *tc) CuAssertPtrNotNull(tc, mt->types); CuAssertStrEquals(tc, "string", mt->types[0]->name); CuAssertStrEquals(tc, "int", mt->types[1]->name); - test_cleanup(); + test_teardown(); } CuSuite *get_message_suite(void) diff --git a/src/util/mt19937ar.c b/src/util/mt19937ar.c index 4fbd3f70d..0dda925ca 100644 --- a/src/util/mt19937ar.c +++ b/src/util/mt19937ar.c @@ -41,8 +41,6 @@ email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space) */ -#include - /* Period parameters */ #define N 624 #define M 397 diff --git a/src/util/nrmessage.c b/src/util/nrmessage.c index 4b7c5ea75..376731713 100644 --- a/src/util/nrmessage.c +++ b/src/util/nrmessage.c @@ -16,7 +16,6 @@ #include "nrmessage_struct.h" /* util includes */ -#include "bsdstring.h" #include "log.h" #include "message.h" #include "language.h" @@ -91,7 +90,7 @@ const nrsection *section_add(const char *name) } if (!*mcp) { nrsection *mc = calloc(sizeof(nrsection), 1); - mc->name = strdup(name); + mc->name = str_strdup(name); *mcp = mc; } return *mcp; @@ -130,14 +129,14 @@ const char *string, int level, const char *section) nrt->section = NULL; nrtypes[hash] = nrt; assert(string && *string); - nrt->string = strdup(string); + nrt->string = str_strdup(string); *c = '\0'; for (i = 0; i != mtype->nparameters; ++i) { if (i != 0) *c++ = ' '; - c += strlcpy(c, mtype->pnames[i], sizeof(zNames)-(c-zNames)); + c += str_strlcpy(c, mtype->pnames[i], sizeof(zNames)-(c-zNames)); } - nrt->vars = strdup(zNames); + nrt->vars = str_strdup(zNames); } } @@ -151,7 +150,7 @@ size_t size, const void *userdata) const char *m = translate(nrt->string, userdata, nrt->vars, msg->parameters); if (m) { - return strlcpy((char *)buffer, m, size); + return str_strlcpy((char *)buffer, m, size); } else { log_error("Couldn't render message %s\n", nrt->mtype->name); diff --git a/src/util/parser.c b/src/util/parser.c index 46a9d3a28..1ba913c2c 100644 --- a/src/util/parser.c +++ b/src/util/parser.c @@ -16,6 +16,8 @@ typedef struct parser_state { const char *current_token; struct parser_state *next; + void *data; + void(*dtor)(void *); } parser_state; static parser_state *states; @@ -50,17 +52,26 @@ static int eatwhitespace_c(const char **str_p) return ret; } -void init_tokens_str(const char *initstr) +void init_tokens_ex(const char *initstr, void *data, void (*dtor)(void *)) { if (states == NULL) { - states = malloc(sizeof(parser_state)); + states = calloc(1, sizeof(parser_state)); } + else if (states->dtor) { + states->dtor(states->data); + } + states->dtor = dtor; + states->data = data; states->current_token = initstr; } +void init_tokens_str(const char *initstr) { + init_tokens_ex(initstr, NULL, NULL); +} + void parser_pushstate(void) { - parser_state *new_state = malloc(sizeof(parser_state)); + parser_state *new_state = calloc(1, sizeof(parser_state)); new_state->current_token = NULL; new_state->next = states; states = new_state; @@ -69,6 +80,9 @@ void parser_pushstate(void) void parser_popstate(void) { parser_state *new_state = states->next; + if (states->dtor) { + states->dtor(states->data); + } free(states); states = new_state; } @@ -232,7 +246,7 @@ int getint(void) return s ? atoi(s) : 0; } -unsigned int getuint(void) +int getuint(void) { int n = getint(); return (n < 0) ? 0 : n; @@ -254,7 +268,7 @@ unsigned int atoip(const char *s) int n; assert(s); - n = (s[0] >='0' && s[0]<='9'); + n = (s[0] >= '0' && s[0] <= '9'); n = n ? atoi(s) : 0; if (n < 0) diff --git a/src/util/parser.h b/src/util/parser.h index 0c8306931..7242da1bb 100644 --- a/src/util/parser.h +++ b/src/util/parser.h @@ -18,6 +18,7 @@ extern "C" { #endif + void init_tokens_ex(const char *initstr, void *data, void(*dtor)(void *)); void init_tokens_str(const char *initstr); /* initialize token parsing */ void skip_token(void); const char *parse_token_depr(const char **str); @@ -27,7 +28,7 @@ extern "C" { bool parser_end(void); const char *getstrtoken(void); const char *gettoken(char *lbuf, size_t bufsize); - unsigned int getuint(void); + int getuint(void); int getint(void); int getid(void); unsigned int atoip(const char *s); diff --git a/src/util/path.c b/src/util/path.c new file mode 100644 index 000000000..3ede6b4ee --- /dev/null +++ b/src/util/path.c @@ -0,0 +1,26 @@ +#ifdef _MSC_VER +#include +#endif + +#include "path.h" +#include "strings.h" + +#include +#include + +char * path_join(const char *p1, const char *p2, char *dst, size_t len) { + size_t sz; + assert(p1 && p2); + assert(p2 != dst); + if (dst == p1) { + sz = strlen(p1); + } + else { + sz = str_strlcpy(dst, p1, len); + } + assert(sz < len); + dst[sz++] = PATH_DELIM; + str_strlcpy(dst + sz, p2, len - sz); + return dst; +} + diff --git a/src/util/path.h b/src/util/path.h new file mode 100644 index 000000000..58e505df9 --- /dev/null +++ b/src/util/path.h @@ -0,0 +1,10 @@ + +#include + +#ifdef WIN32 +#define PATH_DELIM '\\' +#else +#define PATH_DELIM '/' +#endif + +char * path_join(const char *p1, const char *p2, char *dst, size_t len); diff --git a/src/util/rand.c b/src/util/rand.c index 441461068..f409cd0bb 100644 --- a/src/util/rand.c +++ b/src/util/rand.c @@ -28,6 +28,11 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include +/* do not use M_PI, use one of these instead: */ +#define PI_F 3.1415926535897932384626433832795F +#define PI_D 3.1415926535897932384626433832795 +#define PI_L 3.1415926535897932384626433832795L + int lovar(double xpct_x2) { int n = (int)(xpct_x2 * 500) + 1; diff --git a/src/util/rng.test.c b/src/util/rng.test.c index e5bedde81..34e530c5e 100644 --- a/src/util/rng.test.c +++ b/src/util/rng.test.c @@ -1,3 +1,6 @@ +#ifdef _MSC_VER +#include +#endif #include #include diff --git a/src/util/strings.c b/src/util/strings.c index 4e7e17aa4..b33f657ef 100644 --- a/src/util/strings.c +++ b/src/util/strings.c @@ -16,16 +16,101 @@ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. **/ +#ifdef _MSC_VER #include - +#endif #include "strings.h" #include "assert.h" /* libc includes */ -#include +#include +#include #include #include +#ifdef HAVE_LIBBSD +#include +#else +#include +#endif + +size_t str_strlcpy(char *dst, const char *src, size_t len) +{ +#ifdef HAVE_BSDSTRING + return strlcpy(dst, src, len); +#else + register char *d = dst; + register const char *s = src; + register size_t n = len; + + assert(src); + assert(dst); + /* Copy as many bytes as will fit */ + if (n != 0 && --n != 0) { + do { + if ((*d++ = *s++) == 0) + break; + } while (--n != 0); + } + + /* Not enough room in dst, add NUL and traverse rest of src */ + if (n == 0) { + if (len != 0) + *d = '\0'; /* NUL-terminate dst */ + while (*s++); + } + + return (s - src - 1); /* count does not include NUL */ +#endif +} + +size_t str_strlcat(char *dst, const char *src, size_t len) +{ +#ifdef HAVE_BSDSTRING + return strlcat(dst, src, len); +#else + register char *d = dst; + register const char *s = src; + register size_t n = len; + size_t dlen; + + /* Find the end of dst and adjust bytes left but don't go past end */ + while (*d != '\0' && n-- != 0) + d++; + dlen = d - dst; + n = len - dlen; + + if (n == 0) + return (dlen + strlen(s)); + while (*s != '\0') { + if (n != 1) { + *d++ = *s; + n--; + } + s++; + } + *d = '\0'; + + return (dlen + (s - src)); /* count does not include NUL */ +#endif +} + +size_t str_slprintf(char * dst, size_t size, const char * format, ...) +{ + va_list args; + int result; + + va_start(args, format); + result = vsnprintf(dst, size, format, args); + va_end(args); + if (result < 0 || result >= (int)size) { + dst[size - 1] = '\0'; + return size; + } + + return (size_t)result; +} + char *set_string(char **s, const char *neu) { if (neu == NULL) { @@ -45,7 +130,40 @@ char *set_string(char **s, const char *neu) return *s; } -unsigned int hashstring(const char *s) +void str_replace(char *buffer, size_t size, const char *tmpl, const char *var, const char *value) +{ + size_t val_len = strlen(value); + size_t var_len = strlen(var); + char *s = buffer; + while (buffer + size > s) { + char *p = strstr(tmpl, var); + size_t len; + if (p) { + len = p - tmpl; + } + else { + len = strlen(tmpl); + } + if (len < size) { + memmove(s, tmpl, len); + tmpl += len; + s += len; + size -= len; + if (p && val_len < size) { + tmpl += var_len; + memmove(s, value, val_len); + s += val_len; + size -= val_len; + } + } + if (!p) { + break; + } + } + *s = 0; +} + +unsigned int str_hash(const char *s) { unsigned int key = 0; assert(s); @@ -55,7 +173,7 @@ unsigned int hashstring(const char *s) return key & 0x7FFFFFFF; } -const char *escape_string(const char *str, char *buffer, +const char *str_escape(const char *str, char *buffer, size_t len) { const char *start = strchr(str, '\"'); @@ -117,3 +235,57 @@ unsigned int wang_hash(unsigned int a) a = a ^ (a >> 16); return a; } + +char *str_strdup(const char *s) { +#ifdef HAVE_STRDUP + return strdup(s); +#elif defined(_MSC_VER) + return _strdup(s); +#else + size_t len = strlen(s); + char *dup = malloc(len+1); + memcpy(dup, s, len+1); + return dup; +#endif +} + +void sbs_init(struct sbstring *sbs, char *buffer, size_t size) +{ + assert(sbs); + assert(size>0); + sbs->begin = buffer; + sbs->size = size; + sbs->end = buffer; + buffer[0] = '\0'; +} + +void sbs_strncat(struct sbstring *sbs, const char *str, size_t size) +{ + size_t len; + assert(sbs); + len = sbs->size - (sbs->end - sbs->begin) - 1; + if (len < size) { + size = len; + } + memcpy(sbs->end, str, size); + sbs->end[size] = '\0'; + sbs->end += size; +} + +void sbs_strcat(struct sbstring *sbs, const char *str) +{ + size_t len; + assert(sbs); + len = sbs->size - (sbs->end - sbs->begin); + len = str_strlcpy(sbs->end, str, len); + sbs->end += len; +} + +void sbs_strcpy(struct sbstring *sbs, const char *str) +{ + size_t len = str_strlcpy(sbs->begin, str, sbs->size); + if (len >= sbs->size) { + len = sbs->size - 1; + } + sbs->end = sbs->begin + len; +} diff --git a/src/util/strings.h b/src/util/strings.h index 05a435e2c..76bc5a12a 100644 --- a/src/util/strings.h +++ b/src/util/strings.h @@ -25,12 +25,30 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif + void str_replace(char *buffer, size_t size, const char *tmpl, const char *var, const char *value); + const char *str_escape(const char *str, char *buffer, size_t len); char *set_string(char **s, const char *neu); - unsigned int hashstring(const char *s); - const char *escape_string(const char *str, char *buffer, size_t len); + unsigned int str_hash(const char *s); + size_t str_slprintf(char * dst, size_t size, const char * format, ...); + size_t str_strlcpy(char *dst, const char *src, size_t len); + size_t str_strlcat(char *dst, const char *src, size_t len); + char *str_strdup(const char *s); + unsigned int jenkins_hash(unsigned int a); unsigned int wang_hash(unsigned int a); + /* static buffered string */ + typedef struct sbstring { + size_t size; + char *begin; + char *end; + } sbstring; + + void sbs_init(struct sbstring *sbs, char *buffer, size_t size); + void sbs_strcat(struct sbstring *sbs, const char *str); + void sbs_strncat(struct sbstring *sbs, const char *str, size_t size); + void sbs_strcpy(struct sbstring *sbs, const char *str); + /* benchmark for units: * JENKINS_HASH: 5.25 misses/hit (with good cache behavior) * WANG_HASH: 5.33 misses/hit (with good cache behavior) @@ -48,6 +66,7 @@ extern "C" { #define HASH1 JENKINS_HASH1 #define HASH2 JENKINS_HASH2 +#define slprintf str_slprintf #ifdef __cplusplus } diff --git a/src/util/strings.test.c b/src/util/strings.test.c index bcee29e47..89c880a70 100644 --- a/src/util/strings.test.c +++ b/src/util/strings.test.c @@ -1,24 +1,131 @@ +#ifdef _MSC_VER +#include +#endif #include + #include +#include #include #include #include "strings.h" -static void test_escape_string(CuTest * tc) +static void test_str_escape(CuTest * tc) { char scratch[64]; - CuAssertStrEquals(tc, "12345678901234567890", escape_string("12345678901234567890", scratch, 16)); - CuAssertStrEquals(tc, "123456789\\\"12345", escape_string("123456789\"1234567890", scratch, 16)); - CuAssertStrEquals(tc, "1234567890123456", escape_string("1234567890123456\"890", scratch, 16)); - CuAssertStrEquals(tc, "hello world", escape_string("hello world", scratch, sizeof(scratch))); - CuAssertStrEquals(tc, "hello \\\"world\\\"", escape_string("hello \"world\"", scratch, sizeof(scratch))); - CuAssertStrEquals(tc, "\\\"\\\\", escape_string("\"\\", scratch, sizeof(scratch))); - CuAssertStrEquals(tc, "\\\\", escape_string("\\", scratch, sizeof(scratch))); + CuAssertStrEquals(tc, "12345678901234567890", str_escape("12345678901234567890", scratch, 16)); + CuAssertStrEquals(tc, "123456789\\\"12345", str_escape("123456789\"1234567890", scratch, 16)); + CuAssertStrEquals(tc, "1234567890123456", str_escape("1234567890123456\"890", scratch, 16)); + CuAssertStrEquals(tc, "hello world", str_escape("hello world", scratch, sizeof(scratch))); + CuAssertStrEquals(tc, "hello \\\"world\\\"", str_escape("hello \"world\"", scratch, sizeof(scratch))); + CuAssertStrEquals(tc, "\\\"\\\\", str_escape("\"\\", scratch, sizeof(scratch))); + CuAssertStrEquals(tc, "\\\\", str_escape("\\", scratch, sizeof(scratch))); +} + +static void test_str_replace(CuTest * tc) +{ + char result[64]; + str_replace(result, sizeof(result), "Hello $who!", "$who", "World"); + CuAssertStrEquals(tc, "Hello World!", result); +} + +static void test_str_hash(CuTest * tc) +{ + CuAssertIntEquals(tc, 0, str_hash("")); + CuAssertIntEquals(tc, 140703196, str_hash("Hodor")); +} + +static void test_str_slprintf(CuTest * tc) +{ + char buffer[32]; + + memset(buffer, 0x7f, sizeof(buffer)); + + CuAssertTrue(tc, slprintf(buffer, 4, "%s", "herpderp") > 3); + CuAssertStrEquals(tc, "her", buffer); + + CuAssertIntEquals(tc, 4, (int)str_slprintf(buffer, 8, "%s", "herp")); + CuAssertStrEquals(tc, "herp", buffer); + CuAssertIntEquals(tc, 0x7f, buffer[5]); + + CuAssertIntEquals(tc, 8, (int)str_slprintf(buffer, 8, "%s", "herpderp")); + CuAssertStrEquals(tc, "herpder", buffer); + CuAssertIntEquals(tc, 0x7f, buffer[8]); +} + +static void test_str_strlcat(CuTest * tc) +{ + char buffer[32]; + + memset(buffer, 0x7f, sizeof(buffer)); + + buffer[0] = '\0'; + CuAssertIntEquals(tc, 4, (int)str_strlcat(buffer, "herp", 4)); + CuAssertStrEquals(tc, "her", buffer); + + buffer[0] = '\0'; + CuAssertIntEquals(tc, 4, (int)str_strlcat(buffer, "herp", 8)); + CuAssertStrEquals(tc, "herp", buffer); + CuAssertIntEquals(tc, 0x7f, buffer[5]); + + CuAssertIntEquals(tc, 8, (int)str_strlcat(buffer, "derp", 8)); + CuAssertStrEquals(tc, "herpder", buffer); + CuAssertIntEquals(tc, 0x7f, buffer[8]); +} + +static void test_str_strlcpy(CuTest * tc) +{ + char buffer[32]; + + memset(buffer, 0x7f, sizeof(buffer)); + + CuAssertIntEquals(tc, 4, (int)str_strlcpy(buffer, "herp", 4)); + CuAssertStrEquals(tc, "her", buffer); + + CuAssertIntEquals(tc, 4, (int)str_strlcpy(buffer, "herp", 8)); /*-V666 */ + CuAssertStrEquals(tc, "herp", buffer); + CuAssertIntEquals(tc, 0x7f, buffer[5]); + + CuAssertIntEquals(tc, 8, (int)str_strlcpy(buffer, "herpderp", 8)); + CuAssertStrEquals(tc, "herpder", buffer); + CuAssertIntEquals(tc, 0x7f, buffer[8]); + errno = 0; +} + +static void test_sbstring(CuTest * tc) +{ + char buffer[16]; + sbstring sbs; + sbs_init(&sbs, buffer, sizeof(buffer)); + CuAssertStrEquals(tc, "", sbs.begin); + sbs_strcpy(&sbs, "Hodor"); + CuAssertStrEquals(tc, "Hodor", sbs.begin); + sbs_strcat(&sbs, "Hodor"); + CuAssertStrEquals(tc, "HodorHodor", sbs.begin); + sbs_strcpy(&sbs, "Hodor"); + CuAssertStrEquals(tc, "Hodor", sbs.begin); + sbs_strcpy(&sbs, "12345678901234567890"); + CuAssertStrEquals(tc, "123456789012345", sbs.begin); + CuAssertPtrEquals(tc, sbs.begin + sbs.size - 1, sbs.end); + sbs_strcat(&sbs, "12345678901234567890"); + CuAssertStrEquals(tc, "123456789012345", sbs.begin); + CuAssertPtrEquals(tc, buffer, sbs.begin); + sbs_strcpy(&sbs, "1234567890"); + CuAssertStrEquals(tc, "1234567890", sbs.begin); + sbs_strncat(&sbs, "1234567890", 4); + CuAssertStrEquals(tc, "12345678901234", sbs.begin); + sbs_strncat(&sbs, "567890", 6); + CuAssertStrEquals(tc, "123456789012345", sbs.begin); } CuSuite *get_strings_suite(void) { CuSuite *suite = CuSuiteNew(); - SUITE_ADD_TEST(suite, test_escape_string); + SUITE_ADD_TEST(suite, test_str_hash); + SUITE_ADD_TEST(suite, test_str_escape); + SUITE_ADD_TEST(suite, test_str_replace); + SUITE_ADD_TEST(suite, test_str_slprintf); + SUITE_ADD_TEST(suite, test_str_strlcat); + SUITE_ADD_TEST(suite, test_str_strlcpy); + SUITE_ADD_TEST(suite, test_sbstring); return suite; } diff --git a/src/util/translation.c b/src/util/translation.c index 290e28c16..da26806fe 100644 --- a/src/util/translation.c +++ b/src/util/translation.c @@ -9,13 +9,16 @@ This program may not be used, modified or distributed without prior permission by the authors of Eressea. */ +#ifdef _MSC_VER #include +#endif #include "translation.h" -#include "bsdstring.h" +#include "strings.h" #include "critbit.h" #include "log.h" +#include "macros.h" #include "assert.h" /* libc includes */ @@ -161,12 +164,12 @@ static void free_functions(void) void add_function(const char *symbol, evalfun parse) { - char buffer[64]; + char token[64]; size_t len = strlen(symbol); - assert(len + 1 + sizeof(parse) <= sizeof(buffer)); - len = cb_new_kv(symbol, len, &parse, sizeof(parse), buffer); - cb_insert(&functions, buffer, len); + assert(len + 1 + sizeof(parse) <= sizeof(token)); + len = cb_new_kv(symbol, len, &parse, sizeof(parse), token); + cb_insert(&functions, token, len); } static evalfun find_function(const char *symbol) @@ -288,7 +291,7 @@ static const char *parse_string(opstack ** stack, const char *in, if (ic == NULL) return NULL; c = (char *)opop_v(stack); - bytes = (c ? strlcpy(oc, c, size) : 0); + bytes = (c ? str_strlcpy(oc, c, size) : 0); if (bytes < size) oc += bytes; else diff --git a/src/util/umlaut.c b/src/util/umlaut.c index 27f7bc67d..1f9e32b1f 100644 --- a/src/util/umlaut.c +++ b/src/util/umlaut.c @@ -21,7 +21,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "assert.h" #include "log.h" -#include "bsdstring.h" +#include "strings.h" #include "unicode.h" #include @@ -212,7 +212,7 @@ void addtoken(tnode ** root, const char *str, variant id) if (lcs == replace[i].ucs) { char zText[1024]; memcpy(zText, replace[i].str, 3); - strlcpy(zText + 2, (const char *)str + len, sizeof(zText)-2); + str_strlcpy(zText + 2, (const char *)str + len, sizeof(zText)-2); addtoken(root, zText, id); break; } diff --git a/src/util/umlaut.test.c b/src/util/umlaut.test.c index 959960509..0c94ea87a 100644 --- a/src/util/umlaut.test.c +++ b/src/util/umlaut.test.c @@ -1,3 +1,6 @@ +#ifdef _MSC_VER +#include +#endif #include #include #include diff --git a/src/util/variant.c b/src/util/variant.c index af5d690f4..885228847 100644 --- a/src/util/variant.c +++ b/src/util/variant.c @@ -1,7 +1,9 @@ +#ifdef _MSC_VER #include +#endif + #include "variant.h" -#include #include #include diff --git a/src/util/xml.c b/src/util/xml.c index 644698119..ec72179c3 100644 --- a/src/util/xml.c +++ b/src/util/xml.c @@ -16,10 +16,8 @@ #include "log.h" #include "assert.h" -#ifdef USE_LIBXML2 #include #include -#endif /* libc includes */ #include @@ -27,7 +25,6 @@ #include #include -#ifdef USE_LIBXML2 int xml_ivalue(xmlNodePtr node, const char *name, int dflt) { int i = dflt; @@ -110,11 +107,9 @@ void xml_register_callback(xml_callback callback) insert = &(*insert)->next; *insert = reader; } -#endif int read_xml(const char *filename, const char *catalog) { -#ifdef USE_LIBXML2 xml_reader *reader = xmlReaders; xmlDocPtr doc; int result; @@ -141,8 +136,4 @@ int read_xml(const char *filename, const char *catalog) } xmlFreeDoc(doc); return result; -#else - log_error("LIBXML2 disabled, cannot read %s.\n", filename); - return -1; -#endif } diff --git a/src/util/xml.h b/src/util/xml.h index bd22e3e0a..f2dc5fda5 100644 --- a/src/util/xml.h +++ b/src/util/xml.h @@ -19,7 +19,6 @@ extern "C" { #endif -#ifdef USE_LIBXML2 /* new xml functions: */ #include @@ -30,7 +29,6 @@ extern "C" { double xml_fvalue(xmlNodePtr node, const char *name, double dflt); int xml_ivalue(xmlNodePtr node, const char *name, int dflt); bool xml_bvalue(xmlNodePtr node, const char *name, bool dflt); -#endif void xml_done(void); int read_xml(const char *filename, const char *catalog); diff --git a/src/volcano.c b/src/volcano.c index db7166de0..df70a864f 100644 --- a/src/volcano.c +++ b/src/volcano.c @@ -106,8 +106,8 @@ damage_unit(unit * u, const char *dam, bool physical, bool magic) int damage = dice_rand(dam); if (magic) { variant magres = magic_resistance(u); - magres = frac_sub(frac_make(1, 1), magres); - damage = damage * magres.sa[0] / magres.sa[1]; + int save = magres.sa[0] / magres.sa[1]; + damage -= damage * save; } if (physical) { damage -= nb_armor(u, i); @@ -133,8 +133,8 @@ damage_unit(unit * u, const char *dam, bool physical, bool magic) change_effect(u, oldpotiontype[P_HEAL], -1); heiltrank = 1; } - else if (i_get(u->items, oldpotiontype[P_HEAL]->itype) > 0) { - i_change(&u->items, oldpotiontype[P_HEAL]->itype, -1); + else if (i_get(u->items, oldpotiontype[P_HEAL]) > 0) { + i_change(&u->items, oldpotiontype[P_HEAL], -1); change_effect(u, oldpotiontype[P_HEAL], 3); heiltrank = 1; } @@ -225,7 +225,7 @@ volcano_destruction(region * volcano, region * r, const char *damage) if (!fval(u->faction, FFL_SELECT)) { fset(u->faction, FFL_SELECT); ADDMSG(&u->faction->msgs, msg_message("volcanooutbreaknn", - "region", r)); + "region", volcano)); } } if (u == *up) { @@ -314,3 +314,13 @@ void volcano_update(void) } } } + +bool volcano_module(void) +{ + static int cache; + static bool active; + if (config_changed(&cache)) { + active = config_get_int("modules.volcano", 0) != 0; + } + return active; +} diff --git a/src/volcano.h b/src/volcano.h index d06c381cc..225a76143 100644 --- a/src/volcano.h +++ b/src/volcano.h @@ -27,6 +27,7 @@ extern "C" { void volcano_outbreak(struct region * r, struct region *rn); void volcano_update(void); + bool volcano_module(void); #ifdef __cplusplus } diff --git a/src/volcano.test.c b/src/volcano.test.c index 3afa49651..bc2aa2165 100644 --- a/src/volcano.test.c +++ b/src/volcano.test.c @@ -20,7 +20,7 @@ static void test_volcano_update(CuTest *tc) { const struct terrain_type *t_volcano, *t_active; test_setup(); - mt_register(mt_new_va("volcanostopsmoke", "region:region", 0)); + mt_register(mt_new_va("volcanostopsmoke", "region:region", NULL)); t_volcano = test_create_terrain("volcano", LAND_REGION); t_active = test_create_terrain("activevolcano", LAND_REGION); r = test_create_region(0, 0, t_active); @@ -31,7 +31,7 @@ static void test_volcano_update(CuTest *tc) { CuAssertPtrEquals(tc, r, m->parameters[0].v); CuAssertPtrEquals(tc, (void *)t_volcano, (void *)r->terrain); - test_cleanup(); + test_teardown(); } static void test_volcano_outbreak(CuTest *tc) { @@ -42,13 +42,14 @@ static void test_volcano_outbreak(CuTest *tc) { const struct terrain_type *t_volcano, *t_active; test_setup(); - mt_register(mt_new_va("volcanooutbreak", "regionv:region", "regionn:region", 0)); - mt_register(mt_new_va("volcano_dead", "unit:unit", "region:region", "dead:int", 0)); + mt_register(mt_new_va("volcanooutbreak", "regionv:region", "regionn:region", NULL)); + mt_register(mt_new_va("volcanooutbreaknn", "region:region", NULL)); + mt_register(mt_new_va("volcano_dead", "unit:unit", "region:region", "dead:int", NULL)); t_volcano = test_create_terrain("volcano", LAND_REGION); t_active = test_create_terrain("activevolcano", LAND_REGION); r = test_create_region(0, 0, t_active); rn = test_create_region(1, 0, t_volcano); - f = test_create_faction(0); + f = test_create_faction(NULL); u1 = test_create_unit(f, r); u1->hp = u1->number; u2 = test_create_unit(f, rn); @@ -66,6 +67,9 @@ static void test_volcano_outbreak(CuTest *tc) { CuAssertPtrEquals(tc, r, m->parameters[0].v); CuAssertPtrEquals(tc, rn, m->parameters[1].v); + CuAssertPtrNotNull(tc, m = test_find_messagetype(f->msgs, "volcanooutbreaknn")); + CuAssertPtrEquals(tc, r, m->parameters[0].v); + CuAssertPtrNotNull(tc, m = test_find_messagetype_ex(f->msgs, "volcano_dead", NULL)); CuAssertPtrEquals(tc, u1, m->parameters[0].v); CuAssertPtrEquals(tc, r, m->parameters[1].v); @@ -74,7 +78,7 @@ static void test_volcano_outbreak(CuTest *tc) { CuAssertPtrEquals(tc, u2, m->parameters[0].v); CuAssertPtrEquals(tc, r, m->parameters[1].v); CuAssertIntEquals(tc, 1, m->parameters[2].i); - test_cleanup(); + test_teardown(); } CuSuite *get_volcano_suite(void) diff --git a/src/vortex.c b/src/vortex.c index 773982124..bb30524ef 100644 --- a/src/vortex.c +++ b/src/vortex.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -43,7 +44,7 @@ void register_special_direction(struct locale *lang, const char *name) if (token) { void **tokens = get_translations(lang, UT_SPECDIR); variant var; - char *str = strdup(name); + char *str = str_strdup(name); var.v = str; addtoken((struct tnode **)tokens, token, var); @@ -96,9 +97,9 @@ static int a_readdirection(attrib * a, void *owner, struct gamedata *data) READ_INT(store, &d->y); READ_INT(store, &d->duration); READ_TOK(store, lbuf, sizeof(lbuf)); - d->desc = strdup(lbuf); + d->desc = str_strdup(lbuf); READ_TOK(store, lbuf, sizeof(lbuf)); - d->keyword = strdup(lbuf); + d->keyword = str_strdup(lbuf); d->active = true; return AT_READ_OK; } @@ -153,8 +154,8 @@ attrib *create_special_direction(region * r, region * rt, int duration, d->x = rt->x; d->y = rt->y; d->duration = duration; - d->desc = strdup(desc); - d->keyword = strdup(keyword); + d->desc = str_strdup(desc); + d->keyword = str_strdup(keyword); return a; } diff --git a/src/vortex.test.c b/src/vortex.test.c index b4940b6bc..369a787b5 100644 --- a/src/vortex.test.c +++ b/src/vortex.test.c @@ -35,7 +35,7 @@ static void test_move_to_vortex(CuTest *tc) { CuAssertIntEquals(tc, E_MOVE_NOREGION, movewhere(u, "barf", r1, &r)); CuAssertIntEquals(tc, E_MOVE_OK, movewhere(u, "wirbel", r1, &r)); CuAssertPtrEquals(tc, r2, r); - test_cleanup(); + test_teardown(); } CuSuite *get_vortex_suite(void) diff --git a/src/wormhole.c b/src/wormhole.c index b4dfa7068..2366a7e9c 100644 --- a/src/wormhole.c +++ b/src/wormhole.c @@ -28,10 +28,11 @@ #include #include #include +#include #include #include -#include +#include #include /* libc includes */ diff --git a/src/wormhole.test.c b/src/wormhole.test.c index 4f3036200..eafa86572 100644 --- a/src/wormhole.test.c +++ b/src/wormhole.test.c @@ -9,6 +9,7 @@ #include #include +#include #include @@ -17,12 +18,20 @@ void sort_wormhole_regions(selist *rlist, region **match, int count); void make_wormholes(region **match, int count, const building_type *bt_wormhole); +static void setup_wormholes(void) { + mt_register(mt_new_va("wormhole_appear", "region:region", NULL)); + mt_register(mt_new_va("wormhole_dissolve", "region:region", NULL)); + mt_register(mt_new_va("wormhole_exit", "unit:unit", "region:region", NULL)); + mt_register(mt_new_va("wormhole_requirements", "unit:unit", "region:region", NULL)); +} + static void test_make_wormholes(CuTest *tc) { region *r1, *r2, *match[2]; terrain_type *t_plain; building_type *btype; test_setup(); + setup_wormholes(); t_plain = test_create_terrain("plain", LAND_REGION); btype = test_create_buildingtype("wormhole"); match[0] = r1 = test_create_region(0, 0, t_plain); @@ -36,7 +45,7 @@ static void test_make_wormholes(CuTest *tc) { CuAssertPtrEquals(tc, (void *)r2->buildings->type, (void *)btype); CuAssertPtrEquals(tc, (void *)r1->buildings->attribs->type, (void *)r2->buildings->attribs->type); CuAssertStrEquals(tc, r1->buildings->attribs->type->name, "wormhole"); - test_cleanup(); + test_teardown(); } static void test_sort_wormhole_regions(CuTest *tc) { @@ -45,6 +54,7 @@ static void test_sort_wormhole_regions(CuTest *tc) { selist *rlist = 0; test_setup(); + setup_wormholes(); t_plain = test_create_terrain("plain", LAND_REGION); r1 = test_create_region(0, 0, t_plain); r2 = test_create_region(1, 0, t_plain); @@ -56,7 +66,7 @@ static void test_sort_wormhole_regions(CuTest *tc) { CuAssertPtrEquals(tc, r2, match[0]); CuAssertPtrEquals(tc, r1, match[1]); selist_free(rlist); - test_cleanup(); + test_teardown(); } CuSuite *get_wormhole_suite(void) diff --git a/src/kernel/xmlreader.c b/src/xmlreader.c similarity index 97% rename from src/kernel/xmlreader.c rename to src/xmlreader.c index 18bdedebc..ad01ff7ca 100644 --- a/src/kernel/xmlreader.c +++ b/src/xmlreader.c @@ -12,48 +12,47 @@ without prior permission by the authors of Eressea. #include #include + #include "xmlreader.h" -#include "building.h" +#include "kernel/building.h" +#include "kernel/equipment.h" +#include "kernel/item.h" +#include "kernel/messages.h" +#include "kernel/race.h" +#include "kernel/region.h" +#include "kernel/resources.h" +#include "kernel/ship.h" +#include "kernel/terrain.h" +#include "kernel/skills.h" +#include "kernel/spell.h" +#include "kernel/spellbook.h" + +#include "alchemy.h" +#include "calendar.h" #include "guard.h" -#include "equipment.h" -#include "item.h" #include "keyword.h" -#include "messages.h" -#include "race.h" -#include "region.h" -#include "resources.h" -#include "ship.h" -#include "terrain.h" -#include "skills.h" -#include "spell.h" -#include "spellbook.h" -#include "calendar.h" -#include "prefix.h" #include "move.h" - -#include "vortex.h" +#include "prefix.h" #include #include /* util includes */ #include -#include #include #include #include #include #include #include +#include #include -#ifdef USE_LIBXML2 /* libxml includes */ #include #include #include -#endif /* libc includes */ #include @@ -61,7 +60,6 @@ without prior permission by the authors of Eressea. #include #include -#ifdef USE_LIBXML2 static variant xml_fraction(xmlNodePtr node, const char *name) { xmlChar *propValue = xmlGetProp(node, BAD_CAST name); @@ -251,7 +249,7 @@ construction ** consPtr, construct_t type) if (type == CONS_BUILDING) { propValue = xmlGetProp(node, BAD_CAST "name"); if (propValue != NULL) { - con->name = strdup((const char *)propValue); + con->name = str_strdup((const char *)propValue); xmlFree(propValue); } } @@ -284,13 +282,13 @@ static int parse_buildings(xmlDocPtr doc) { xmlXPathContextPtr xpath = xmlXPathNewContext(doc); xmlXPathObjectPtr buildings; - int i; /* reading eressea/buildings/building */ buildings = xmlXPathEvalExpression(BAD_CAST "/eressea/buildings/building", xpath); if (buildings->nodesetval != NULL) { xmlNodeSetPtr nodes = buildings->nodesetval; + int i; for (i = 0; i != nodes->nodeNr; ++i) { xmlNodePtr node = nodes->nodeTab[i]; xmlChar *propValue; @@ -396,12 +394,12 @@ static int parse_ships(xmlDocPtr doc) { xmlXPathContextPtr xpath = xmlXPathNewContext(doc); xmlXPathObjectPtr ships; - int i; /* reading eressea/ships/ship */ ships = xmlXPathEvalExpression(BAD_CAST "/eressea/ships/ship", xpath); if (ships->nodesetval != NULL) { xmlNodeSetPtr nodes = ships->nodesetval; + int i; for (i = 0; i != nodes->nodeNr; ++i) { xmlNodePtr child, node = nodes->nodeTab[i]; xmlChar *propValue; @@ -424,6 +422,8 @@ static int parse_ships(xmlDocPtr doc) st->flags |= SFL_FLY; if (xml_bvalue(node, "opensea", false)) st->flags |= SFL_OPENSEA; + if (xml_bvalue(node, "speedy", false)) + st->flags |= SFL_SPEEDY; st->fishing = xml_ivalue(node, "fishing", st->fishing); st->cptskill = xml_ivalue(node, "cptskill", st->cptskill); st->minskill = xml_ivalue(node, "minskill", st->minskill); @@ -484,12 +484,11 @@ static int parse_ships(xmlDocPtr doc) return 0; } -static potion_type *xml_readpotion(xmlXPathContextPtr xpath, item_type * itype) +static void xml_readpotion(xmlXPathContextPtr xpath, item_type * itype) { int level = xml_ivalue(xpath->node, "level", 0); - assert(level > 0); - return new_potiontype(itype, level); + new_potiontype(itype, level); } static luxury_type *xml_readluxury(xmlXPathContextPtr xpath, item_type * itype) @@ -526,7 +525,6 @@ static weapon_type *xml_readweapon(xmlXPathContextPtr xpath, item_type * itype) xmlChar *propValue; int k; skill_t sk; - int minskill = xml_ivalue(node, "minskill", 1); int offmod = xml_ivalue(node, "offmod", 0); int defmod = xml_ivalue(node, "defmod", 0); int reload = xml_ivalue(node, "reload", 0); @@ -558,8 +556,7 @@ static weapon_type *xml_readweapon(xmlXPathContextPtr xpath, item_type * itype) xmlFree(propValue); wtype = - new_weapontype(itype, flags, magres, NULL, offmod, defmod, reload, sk, - minskill); + new_weapontype(itype, flags, magres, NULL, offmod, defmod, reload, sk); /* reading weapon/damage */ xpath->node = node; @@ -576,7 +573,7 @@ static weapon_type *xml_readweapon(xmlXPathContextPtr xpath, item_type * itype) xmlFree(propValue); propValue = xmlGetProp(node, BAD_CAST "value"); - wtype->damage[pos] = strdup((const char *)propValue); /* TODO: this is a memory leak */ + wtype->damage[pos] = str_strdup((const char *)propValue); /* TODO: this is a memory leak */ if (k == 0) wtype->damage[1 - pos] = wtype->damage[pos]; xmlFree(propValue); @@ -744,7 +741,7 @@ static item_type *xml_readitem(xmlXPathContextPtr xpath, resource_type * rtype) itype->flags |= ITF_CANUSE; } xpath->node = result->nodesetval->nodeTab[0]; - rtype->ptype = xml_readpotion(xpath, itype); + xml_readpotion(xpath, itype); } xmlXPathFreeObject(result); @@ -810,7 +807,6 @@ static int parse_resources(xmlDocPtr doc) resource_type *rtype; unsigned int flags = RTF_NONE; xmlXPathObjectPtr result; - int k; if (xml_bvalue(node, "pooled", true)) flags |= RTF_POOLED; @@ -828,7 +824,8 @@ static int parse_resources(xmlDocPtr doc) /* reading eressea/resources/resource/function */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "function", xpath); - if (result->nodesetval != NULL) + if (result->nodesetval != NULL) { + int k; for (k = 0; k != result->nodesetval->nodeNr; ++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; pf_generic fun; @@ -852,6 +849,7 @@ static int parse_resources(xmlDocPtr doc) } xmlFree(propValue); } + } xmlXPathFreeObject(result); if (xml_bvalue(node, "material", false)) { @@ -1202,13 +1200,13 @@ static int parse_spells(xmlDocPtr doc) propValue = xmlGetProp(node, BAD_CAST "parameters"); if (propValue) { - sp->parameter = strdup((const char *)propValue); + sp->parameter = str_strdup((const char *)propValue); xmlFree(propValue); } propValue = xmlGetProp(node, BAD_CAST "syntax"); if (propValue) { - sp->syntax = strdup((const char *)propValue); + sp->syntax = str_strdup((const char *)propValue); xmlFree(propValue); } #ifdef TODO /* no longer need it, spellbooks! */ @@ -1357,7 +1355,7 @@ static int parse_races(xmlDocPtr doc) propValue = xmlGetProp(node, BAD_CAST "damage"); assert(propValue != NULL); - rc->def_damage = strdup((const char *)propValue); + rc->def_damage = str_strdup((const char *)propValue); xmlFree(propValue); rc->magres = frac_make(xml_ivalue(node, "magres", 100), 100); @@ -1434,10 +1432,6 @@ static int parse_races(xmlDocPtr doc) rc->flags |= RCF_DRAGON; if (xml_bvalue(node, "shipspeed", false)) rc->flags |= RCF_SHIPSPEED; - if (xml_bvalue(node, "stonegolem", false)) - rc->flags |= RCF_STONEGOLEM; - if (xml_bvalue(node, "irongolem", false)) - rc->flags |= RCF_IRONGOLEM; if (xml_bvalue(node, "giveperson", false)) rc->ec_flags |= ECF_GIVEPERSON; @@ -1449,6 +1443,10 @@ static int parse_races(xmlDocPtr doc) rc->ec_flags |= ECF_REC_ETHEREAL; if (xml_bvalue(node, "recruitunlimited", false)) rc->ec_flags |= ECF_REC_UNLIMITED; + if (xml_bvalue(node, "stonegolem", false)) + rc->ec_flags |= ECF_STONEGOLEM; + if (xml_bvalue(node, "irongolem", false)) + rc->ec_flags |= ECF_IRONGOLEM; if (xml_bvalue(node, "equipment", false)) rc->battle_flags |= BF_EQUIPMENT; /* TODO: invert this flag, so rc_get_or_create gets simpler */ @@ -1552,7 +1550,7 @@ static int parse_races(xmlDocPtr doc) propValue = xmlGetProp(node, BAD_CAST "damage"); if (propValue != NULL) { - attack->data.dice = strdup((const char *)propValue); + attack->data.dice = str_strdup((const char *)propValue); xmlFree(propValue); } else { @@ -1615,7 +1613,7 @@ static int parse_messages(xmlDocPtr doc) (const char *)propType); xmlFree(propName); xmlFree(propType); - argv[k] = strdup(zBuffer); + argv[k] = str_strdup(zBuffer); } argv[result->nodesetval->nodeNr] = NULL; } @@ -1760,4 +1758,3 @@ void register_xmlreader(void) xml_register_callback(parse_strings); xml_register_callback(parse_messages); } -#endif diff --git a/src/kernel/xmlreader.h b/src/xmlreader.h similarity index 100% rename from src/kernel/xmlreader.h rename to src/xmlreader.h diff --git a/tests/drmemory.bat b/tests/drmemory.bat index 66ca98c38..2a2874f1d 100644 --- a/tests/drmemory.bat +++ b/tests/drmemory.bat @@ -1,6 +1,7 @@ cd c:\users\enno\documents\eressea\git\tests "C:\Program Files (x86)\Dr. Memory\bin64\drmemory.exe" ..\build-vs14\eressea\Debug\eressea.exe -t184 test-turn.lua +REM "C:\Program Files (x86)\Dr. Memory\bin64\drmemory.exe" ..\build-vs14\eressea\Debug\test_eressea.exe -t184 test-turn.lua del /q reports del /q datum htpasswd parteien parteien.full passwd score turn diff --git a/vs2015-build.bat b/vs2015-build.bat index 262d498bf..1ad2c8da2 100644 --- a/vs2015-build.bat +++ b/vs2015-build.bat @@ -9,5 +9,5 @@ IF exist build-vs%VSVERSION% goto HAVEDIR mkdir build-vs%VSVERSION% :HAVEDIR cd build-vs%VSVERSION% -"%ProgramFiles%\CMake\bin\cmake.exe" -G "Visual Studio %VSVERSION%" -DCMAKE_PREFIX_PATH="%ProgramFiles(x86)%/Lua/5.1;%ERESSEA%/dependencies-win32" -DCMAKE_MODULE_PATH="%SRCDIR%/cmake/Modules" -DCMAKE_SUPPRESS_REGENERATION=TRUE .. +"%ProgramFiles%\CMake\bin\cmake.exe" -G "Visual Studio %VSVERSION%" -DCMAKE_PREFIX_PATH="%ProgramFiles(x86)%\Lua\5.1;%ERESSEA%\dependencies-win32" -DCMAKE_SUPPRESS_REGENERATION=TRUE .. PAUSE