diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 000000000..16ec084e0
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,16 @@
+# Geplante Aenderungen in zukuenftigen Eressea-Versionen
+
+Als Anhaltspunkt fuer die Empfaenger der woechentlichen Testauswertungnen
+will ich versuchen, die Liste meiner Aenderungen seit dem letzten Release
+zu dokumentieren.
+
+## Version 3.12.0
+
+- [other] optimierte Berechnung der Sichtbarkeit von Leuchttuermen
+- [bug] Einheitenlimit bei GIB PERSON beachten
+- [bug] Einheitenlimit bei ALLIANCE JOIN beachten
+- [rule] Einheiten- und Personenzahl im Report beinhaltet *alle* Einheiten der Partei.
+- [other] Statistik fuer Spielleiter zeigt das Parteisilber nicht mehr an.
+- [other] Berechnung der Message-Ids optimiert.
+
+
diff --git a/conf/calendar.json b/conf/calendar.json
new file mode 100644
index 000000000..43b01351a
--- /dev/null
+++ b/conf/calendar.json
@@ -0,0 +1,22 @@
+{
+ "calendar" : {
+ "months" : [
+ { "storm" : 60, "season" : 2 },
+
+ { "storm" : 10, "season" : 3 },
+ { "storm" : 60, "season" : 3 },
+
+ { "storm" : 10, "season" : 0 },
+ { "storm" : 60, "season" : 0 },
+ { "storm" : 80, "season" : 0 },
+
+ { "storm" : 50, "season" : 1 },
+ { "storm" : 30, "season" : 1 },
+
+ { "storm" : 60, "season" : 2 }
+ ],
+ "weeks" : [
+ "firstweek", "secondweek", "thirdweek"
+ ]
+ }
+}
diff --git a/conf/e2/config.json b/conf/e2/config.json
index f9f9b2df0..fb231e2eb 100644
--- a/conf/e2/config.json
+++ b/conf/e2/config.json
@@ -1,9 +1,10 @@
{
- "include": [
- "keywords.json",
- "prefixes.json",
+ "include": [
+ "keywords.json",
+ "calendar.json",
+ "prefixes.json",
"e2/terrains.json"
- ],
+ ],
"disabled": [
"jsreport"
],
@@ -21,13 +22,12 @@
"GiveRestriction": 3,
"hunger.long": true,
"init_spells": 0,
- "world.era": 2,
- "seed.population.min": 8,
- "seed.population.max": 8,
+ "game.era": 2,
+ "game.start": 184,
"rules.reserve.twophase": true,
"rules.give.max_men": -1,
"rules.check_overload": false,
- "rules.limit.faction": 2500,
+ "rules.limit.faction": 3000,
"rules.maxskills.magic": 5,
"rules.guard.base_stop_prob": 0.30,
"rules.guard.skill_stop_prob": 0.05,
diff --git a/conf/e2/rules.xml b/conf/e2/rules.xml
index 8d0b01b27..7bde2205f 100644
--- a/conf/e2/rules.xml
+++ b/conf/e2/rules.xml
@@ -15,8 +15,6 @@
-
-
diff --git a/conf/e3/config.json b/conf/e3/config.json
index 1cecc89d2..bfd1bd0fc 100644
--- a/conf/e3/config.json
+++ b/conf/e3/config.json
@@ -1,6 +1,7 @@
{
"include": [
"keywords.json",
+ "calendar.json",
"prefixes.json",
"e3/terrains.json"
],
@@ -51,11 +52,11 @@
"recruit.allow_merge": true,
"study.expensivemigrants": true,
"study.speedup": 2,
- "world.era": 3,
- "seed.population.min": 8,
- "seed.population.max": 8,
+ "game.era": 3,
+ "game.start": 1,
"rules.reserve.twophase": true,
"rules.owners.force_leave": false,
+ "rules.wage.function": 2,
"rules.monsters.attack_chance": 0.1,
"rules.transfermen": false,
"stealth.faction.other": false,
@@ -87,7 +88,7 @@
"rules.economy.herbrot": 0,
"rules.region_owner_pay_building": "market harbour lighthouse",
"rules.dwarf_castles": true,
- "rules.limit.faction": 250,
+ "rules.limit.faction": 500,
"rules.grow.formula": 1,
"rules.tactics.formula": 1,
"rules.help.mask": "fight guard money give",
diff --git a/conf/e3/rules.xml b/conf/e3/rules.xml
index 421b54d7a..7fbf7dc6e 100644
--- a/conf/e3/rules.xml
+++ b/conf/e3/rules.xml
@@ -10,7 +10,6 @@
-
@@ -21,14 +20,9 @@
-
-
-
-
-
diff --git a/conf/eressea.ini b/conf/eressea.ini
index b6db180ca..c745631ad 100644
--- a/conf/eressea.ini
+++ b/conf/eressea.ini
@@ -2,11 +2,9 @@
email = eressea-server@kn-bremen.de
sender = Eressea Server
name = Eressea
-base = .
report = reports
verbose = 0
lomem = 0
-debug = 0
memcheck = 0
locales = de,en
diff --git a/doc/gprof-v3.10.0-163-gdfab45d.txt b/doc/gprof-v3.10.0-163-gdfab45d.profile
similarity index 100%
rename from doc/gprof-v3.10.0-163-gdfab45d.txt
rename to doc/gprof-v3.10.0-163-gdfab45d.profile
diff --git a/etc/report-mail.de.txt b/etc/report-mail.de.txt
new file mode 100644
index 000000000..e40d86b53
--- /dev/null
+++ b/etc/report-mail.de.txt
@@ -0,0 +1,10 @@
+Freust Du Dich, dass es diese Woche wieder einen Eressea-Report gibt?
+Möchtest Du dazu beitragen, dass das auch nächste Woche wieder passiert?
+Eressea ist ein freiwilliges gratis-Angebot, und die Spielleitung bezahlt
+seit Jahren die Entwicklung und das Hosting aus eigener Tasche. Wenn Dir
+das etwas wert ist, kannst Du das auf
+https://flattr.com/thing/681354/Eressea zum Ausdruck bringen.
+
+Diese Mail enthält ein Attachment mit Deinem Eressea-Report in
+komprimierter Form. Um ihn zu entpacken benötigst Du ein Programm,
+das ZIP-Archive öffnen kann, wie z.B. 7-Zip (http://www.7-zip.org/)
diff --git a/etc/report-mail.en.txt b/etc/report-mail.en.txt
new file mode 100644
index 000000000..58a8e0c19
--- /dev/null
+++ b/etc/report-mail.en.txt
@@ -0,0 +1,6 @@
+If you feel that getting a report every weekend is worth something to you,
+why not flattr Eressea at https://flattr.com/thing/681354/Eressea ?
+
+This email contains an Attachment with your Eressea report in compressed
+form. To open the attachment, you will need a program that can extract
+ZIP files, e.g. 7-Zip (http://www.7-zip.org/).
diff --git a/etc/report-mail.txt b/etc/report-mail.txt
new file mode 100644
index 000000000..4101243e7
--- /dev/null
+++ b/etc/report-mail.txt
@@ -0,0 +1,14 @@
+Freust Du Dich, dass es diese Woche wieder einen Eressea-Report gibt?
+Möchtest Du dazu beitragen, dass das auch nächste Woche wieder passiert?
+Eressea ist ein freiwilliges gratis-Angebot, und die Spielleitung bezahlt
+seit Jahren die Entwicklung und das Hosting aus eigener Tasche. Wenn Dir
+das etwas wert ist, kannst Du das auf
+https://flattr.com/thing/681354/Eressea zum Ausdruck bringen.
+
+Diese Mail enthält ein Attachment mit Deinem Eressea-Report in
+komprimierter Form. Um ihn zu entpacken benötigst Du ein Programm,
+das ZIP-Archive öffnen kann, wie z.B. 7-Zip (http://www.7-zip.org/)
+
+This email contains an attachment with your Eressea report in compressed
+form. To open the attachment, you will need a program that can extract
+ZIP files, e.g. 7-Zip (http://www.7-zip.org/).
diff --git a/process/cron/crontab b/process/cron/crontab
deleted file mode 100644
index 9d7e155cb..000000000
--- a/process/cron/crontab
+++ /dev/null
@@ -1,17 +0,0 @@
-# Crontab for Eressea on gruenbaer.kn-bremen.de
-
-PATH=/home/eressea/bin:/opt/bin:/usr/local/bin:/usr/bin:/bin
-ERESSEA=/home/eressea/eressea
-ENABLED=yes
-PREVIEW=yes
-CONFIRM=yes
-
-# m h dom mon dow command
-00 00 * * * $HOME/bin/fetchmail.cron
-00 22 * * * $HOME/bin/backup-db.sh
-
-15 21 * * Sat [ "$ENABLED" = "yes" ] && $ERESSEA/server/bin/run-eressea.cron 3
-25 21 * * Sat [ "$ENABLED" = "yes" ] && $ERESSEA/server/bin/run-eressea.cron 4
-35 21 * * Sat [ "$ENABLED" = "yes" ] && $ERESSEA/server/bin/run-eressea.cron 2
-30 07 * * Sun [ "$PREVIEW" = "yes" ] && $ERESSEA/server/bin/preview.cron
-*/5 * * * * [ "$CONFIRM" = "yes" ] && $ERESSEA/server/bin/orders.cron 2 3 4
diff --git a/process/cron/orders.cron b/process/cron/orders.cron
index be573fe86..114a870a5 100755
--- a/process/cron/orders.cron
+++ b/process/cron/orders.cron
@@ -5,6 +5,10 @@
# this here script to make a non-blocking syntax check and reject or
# accept the order file.
+if [ "yes" != "$CONFIRM" ] ; then
+ exit
+fi
+
for GAME in $*
do
if [ "$GAME" == "eressea" ]; then GAME=2 ; fi
diff --git a/process/cron/preview.cron b/process/cron/preview.cron
index 985ddf40b..71ebd0571 100755
--- a/process/cron/preview.cron
+++ b/process/cron/preview.cron
@@ -1,6 +1,8 @@
#!/bin/bash
-[ -z ${ERESSEA} ] && ERESSEA=~/eressea
+[ "$PREVIEW" != "yes" ] && exit
+[ -z ${ERESSEA} ] && ERESSEA=$HOME/eressea
+
branch="develop"
if [ -e ${ERESSEA}/build/.preview ]; then
branch=`cat ${ERESSEA}/build/.preview`
diff --git a/process/cron/run-eressea.cron b/process/cron/run-eressea.cron
index 8b506a633..4ea38184c 100755
--- a/process/cron/run-eressea.cron
+++ b/process/cron/run-eressea.cron
@@ -1,7 +1,11 @@
#!/bin/bash
GAME=$1
-BIN=$HOME/bin
-export ERESSEA=$HOME/eressea
+
+[ "$ENABLED" != "yes" ] && exit
+[ -z ${ERESSEA} ] && ERESSEA=$HOME/eressea
+
+export ERESSEA
+BIN=$ERESSEA/server/bin
TURN=$(cat $ERESSEA/game-$GAME/turn)
if [ ! -e $ERESSEA/game-$GAME/data/$TURN.dat ]; then
echo "data file $TURN is missing, cannot run turn for game $GAME"
@@ -14,6 +18,18 @@ fi
mkdir $REPORTS
cd $ERESSEA/game-$GAME
+
+# wait for the queue lock to go away
+maxt=5
+to=5
+while [ -e orders.queue.lock ] ; do
+ echo "waiting for orders to finish processing."
+ sleep $to
+ let to=$to+$to
+ let mast=$maxt-1
+ [ $maxt -lt 0 ] && break
+done
+
if [ -d test ]; then
touch test/execute.lock
fi
diff --git a/process/orders.cron b/process/orders.cron
deleted file mode 100755
index be573fe86..000000000
--- a/process/orders.cron
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/bin/bash
-
-## this script processes incoming order files.
-# files are delivered into an incoming queue by procmail, then cron runs
-# this here script to make a non-blocking syntax check and reject or
-# accept the order file.
-
-for GAME in $*
-do
- if [ "$GAME" == "eressea" ]; then GAME=2 ; fi
- if [ "$GAME" == "e3a" ]; then GAME=3 ; fi
- if [ -e $HOME/eressea/game-$GAME/orders.queue ]
- then
- $HOME/bin/orders-process $GAME
- fi
-done
diff --git a/process/run-turn b/process/run-turn
index 0c5ee8fd2..c0d0d6a40 100755
--- a/process/run-turn
+++ b/process/run-turn
@@ -1,3 +1,5 @@
+#!/bin/sh
+
GAME=$1
TURN=$2
@@ -12,3 +14,4 @@ echo "running turn $TURN, game $GAME"
$ERESSEA/server/bin/eressea -v3 -t $TURN run-turn.lua
mkdir -p log
ln -f eressea.log log/eressea.log.$TURN
+
diff --git a/process/run-turn.sh b/process/run-turn.sh
deleted file mode 100755
index 9cc4e4ffd..000000000
--- a/process/run-turn.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-GAME=$1
-TURN=$2
-
-if [ ! -d $ERESSEA/game-$GAME ] ; then
- echo "No such game: $GAME"
- exit 1
-fi
-
-cd $ERESSEA/game-$GAME
-if [ -z $TURN ]; then
- TURN=$(cat turn)
-fi
-
-echo "running turn $TURN, game $GAME"
-if [ -d orders.dir.$TURN ]; then
- echo "orders.dir.$TURN already exists"
-else
- mv orders.dir orders.dir.$TURN
- mkdir -p orders.dir
-fi
-ls -1rt orders.dir.$TURN/turn-* | xargs cat > orders.$TURN
-$ERESSEA/bin/eressea -t $TURN run-turn.lua
diff --git a/res/adamantium.xml b/res/adamantium.xml
index 13d08ca99..e1f0643e2 100644
--- a/res/adamantium.xml
+++ b/res/adamantium.xml
@@ -5,10 +5,8 @@
-
-
-
diff --git a/res/buildings/castle-2.xml b/res/buildings/castle-2.xml
index 7b015d199..7e64f88af 100644
--- a/res/buildings/castle-2.xml
+++ b/res/buildings/castle-2.xml
@@ -1,23 +1,21 @@
-
-
-
-
+
+
-
+
-
+
-
+
-
+
-
+
diff --git a/res/buildings/castle.xml b/res/buildings/castle.xml
index 6e9140222..78ce7066c 100644
--- a/res/buildings/castle.xml
+++ b/res/buildings/castle.xml
@@ -1,25 +1,24 @@
-
-
+
-
+
-
+
-
+
-
+
-
+
-
+
diff --git a/res/core/armor/plate.xml b/res/core/armor/plate.xml
index a22064e90..97d855a73 100644
--- a/res/core/armor/plate.xml
+++ b/res/core/armor/plate.xml
@@ -1,7 +1,6 @@
-
-
diff --git a/res/core/calendar.xml b/res/core/calendar.xml
deleted file mode 100644
index d96037698..000000000
--- a/res/core/calendar.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/res/core/common/buildings.xml b/res/core/common/buildings.xml
index 540e9f085..a799ce309 100644
--- a/res/core/common/buildings.xml
+++ b/res/core/common/buildings.xml
@@ -93,7 +93,6 @@
-
@@ -102,6 +101,8 @@
+
+
diff --git a/res/core/common/items.xml b/res/core/common/items.xml
index c903a6b78..35f9af2c5 100644
--- a/res/core/common/items.xml
+++ b/res/core/common/items.xml
@@ -61,16 +61,8 @@
-
- -
-
-
-
-
- -
-
-
+
@@ -78,9 +70,7 @@
- -
-
-
+
@@ -100,39 +90,34 @@
+
+
+
+
+
- -
-
-
+
- -
-
-
+
- -
-
-
+
- -
-
-
+
- -
-
-
+
diff --git a/res/core/common/potions.xml b/res/core/common/potions.xml
index 84b1e5f52..4812727dd 100644
--- a/res/core/common/potions.xml
+++ b/res/core/common/potions.xml
@@ -4,8 +4,7 @@
- -
-
+
-
@@ -15,8 +14,7 @@
- -
-
+
-
@@ -26,8 +24,7 @@
- -
-
+
-
@@ -37,8 +34,7 @@
- -
-
+
-
@@ -48,8 +44,7 @@
- -
-
+
-
@@ -61,8 +56,7 @@
-
-
-
+
-
@@ -74,8 +68,7 @@
-
-
-
+
-
@@ -87,8 +80,7 @@
- -
-
+
-
@@ -100,8 +92,7 @@
- -
-
+
-
@@ -113,8 +104,7 @@
- -
-
+
-
@@ -126,8 +116,7 @@
- -
-
+
-
@@ -139,8 +128,7 @@
- -
-
+
-
@@ -152,8 +140,7 @@
- -
-
+
-
@@ -166,8 +153,7 @@
- -
-
+
-
@@ -181,8 +167,7 @@
- -
-
+
-
diff --git a/res/core/de/strings.xml b/res/core/de/strings.xml
index a39657580..c26bfe03b 100644
--- a/res/core/de/strings.xml
+++ b/res/core/de/strings.xml
@@ -1458,12 +1458,6 @@
Amulette des wahren Sehens
-
- Katzenamulett
-
-
- Katzenamulette
-
Ring der Unsichtbarkeit
@@ -6529,13 +6523,17 @@
Sonnenfeuer
sunfire
-
+
+ neuer Zeitrechnung
+ of the new age
+
+
des zweiten Zeitalters
the second age
-
- neuer Zeitrechnung
- of the new age
+
+ des dritten Zeitalters
+ the third age
diff --git a/res/core/en/strings.xml b/res/core/en/strings.xml
index d1f744df1..dbc4dc611 100644
--- a/res/core/en/strings.xml
+++ b/res/core/en/strings.xml
@@ -444,12 +444,6 @@
amulets of chastity
-
- amulet of the kitten
-
-
- amulets of the kitten
-
amulet of darkness
diff --git a/res/core/fr/strings.xml b/res/core/fr/strings.xml
index c69bb5b75..13e6beb25 100644
--- a/res/core/fr/strings.xml
+++ b/res/core/fr/strings.xml
@@ -458,12 +458,6 @@
amulettes de chasteté
-
- amulette du chaton
-
-
- amulettes du chaton
-
amulette de ténčbres
diff --git a/res/core/messages.xml b/res/core/messages.xml
index 32d8e35a6..5d8a60ef0 100644
--- a/res/core/messages.xml
+++ b/res/core/messages.xml
@@ -5536,8 +5536,8 @@
- "$unit($unit) in $region($region): '$order($command)' - Nur Elfen können diese Bögen herstellen."
- "$unit($unit) in $region($region): '$order($command)' - Only elves can make these bows."
+ "$unit($unit) in $region($region): '$order($command)' - Diesen Gegenstand kann die Einheit nicht herstellen."
+ "$unit($unit) in $region($region): '$order($command)' - This unit cannot produce that."
@@ -5545,8 +5545,8 @@
- "$unit($unit) in $region($region): '$order($command)' - Nur die EMail-Adresse angeben!"
- "$unit($unit) in $region($region): '$order($command)' - Please provide only an email address!"
+ "$unit($unit) in $region($region): '$order($command)' - Diese Rasse kann das nicht herstellen."
+ "$unit($unit) in $region($region): '$order($command)' - This race cannot produce that."
@@ -7678,24 +7678,6 @@
"$unit($unit) plays the bagpipe. Stricken with fear the peasants give $int($money) silver."
-
-
-
-
-
- "$unit($unit) in $region($region) erschafft eine Akademie der Künste."
- "$unit($unit) in $region($region) creates an academy of arts."
-
-
-
-
-
-
-
- "$unit($unit) in $region($region) erschafft eine Skulptur."
- "$unit($unit) in $region($region) creates a sculpture."
-
-
diff --git a/res/core/resources/horse.xml b/res/core/resources/horse.xml
index d7f794491..608fca20a 100644
--- a/res/core/resources/horse.xml
+++ b/res/core/resources/horse.xml
@@ -1,11 +1,6 @@
-
-
-
+
-
-
-
-
diff --git a/res/core/resources/hp.xml b/res/core/resources/hp.xml
index fb1b6e32f..aa0ad4d29 100644
--- a/res/core/resources/hp.xml
+++ b/res/core/resources/hp.xml
@@ -1,5 +1,4 @@
-
diff --git a/res/core/resources/iron.xml b/res/core/resources/iron.xml
index 469840669..1aff826fc 100644
--- a/res/core/resources/iron.xml
+++ b/res/core/resources/iron.xml
@@ -1,11 +1,10 @@
- -
-
-
-
+ -
+
+
+
-
-
+
diff --git a/res/core/resources/laen.xml b/res/core/resources/laen.xml
index 5fbe86549..e584fe485 100644
--- a/res/core/resources/laen.xml
+++ b/res/core/resources/laen.xml
@@ -1,10 +1,8 @@
- -
-
-
-
-
-
-
+ -
+
+
+
+
diff --git a/res/core/resources/log.xml b/res/core/resources/log.xml
index 48662878f..e3710d496 100644
--- a/res/core/resources/log.xml
+++ b/res/core/resources/log.xml
@@ -1,12 +1,8 @@
-
- -
-
-
-
+
+ -
+
+
-
-
-
diff --git a/res/core/resources/mallorn.xml b/res/core/resources/mallorn.xml
index 96892b802..3dff091c6 100644
--- a/res/core/resources/mallorn.xml
+++ b/res/core/resources/mallorn.xml
@@ -1,12 +1,8 @@
-
- -
-
-
-
+
+ -
+
+
-
-
-
diff --git a/res/core/resources/mallornseed.xml b/res/core/resources/mallornseed.xml
index 01b8a3416..7a5a0310f 100644
--- a/res/core/resources/mallornseed.xml
+++ b/res/core/resources/mallornseed.xml
@@ -3,8 +3,4 @@
-
-
-
-
-
diff --git a/res/core/resources/peasant.xml b/res/core/resources/peasant.xml
index 32e1e1ca1..bce23430c 100644
--- a/res/core/resources/peasant.xml
+++ b/res/core/resources/peasant.xml
@@ -1,5 +1,4 @@
-
diff --git a/res/core/resources/seed.xml b/res/core/resources/seed.xml
index 2bda26eeb..99f5f5804 100644
--- a/res/core/resources/seed.xml
+++ b/res/core/resources/seed.xml
@@ -3,8 +3,4 @@
-
-
-
-
-
diff --git a/res/core/resources/stone.xml b/res/core/resources/stone.xml
index 91d3aac5d..e1c5651ed 100644
--- a/res/core/resources/stone.xml
+++ b/res/core/resources/stone.xml
@@ -1,11 +1,9 @@
- -
-
-
-
+ -
+
+
-
diff --git a/res/core/spells.xml b/res/core/spells.xml
index cb7fcf911..59d06a522 100644
--- a/res/core/spells.xml
+++ b/res/core/spells.xml
@@ -10,14 +10,12 @@
-
-
@@ -25,12 +23,10 @@
-
-
@@ -38,19 +34,16 @@
-
-
-
@@ -58,18 +51,15 @@
-
-
-
@@ -77,12 +67,10 @@
-
-
@@ -90,25 +78,21 @@
-
-
-
-
@@ -116,7 +100,6 @@
-
@@ -124,20 +107,17 @@
-
-
-
diff --git a/res/core/weapons/axe.xml b/res/core/weapons/axe.xml
index 80a872ad7..3f97a5b8a 100644
--- a/res/core/weapons/axe.xml
+++ b/res/core/weapons/axe.xml
@@ -1,7 +1,6 @@
-
-
diff --git a/res/core/weapons/greatbow.xml b/res/core/weapons/greatbow.xml
index 10b270e55..452ac0250 100644
--- a/res/core/weapons/greatbow.xml
+++ b/res/core/weapons/greatbow.xml
@@ -1,9 +1,8 @@
+
-
-
-
diff --git a/res/core/weapons/greatsword.xml b/res/core/weapons/greatsword.xml
index cd48b8296..56285f6af 100644
--- a/res/core/weapons/greatsword.xml
+++ b/res/core/weapons/greatsword.xml
@@ -1,7 +1,6 @@
-
-
diff --git a/res/core/weapons/halberd.xml b/res/core/weapons/halberd.xml
index 5025f4793..7abc86902 100644
--- a/res/core/weapons/halberd.xml
+++ b/res/core/weapons/halberd.xml
@@ -1,7 +1,6 @@
-
-
diff --git a/res/core/weapons/lance.xml b/res/core/weapons/lance.xml
index abbb7f31f..4a02bc06f 100644
--- a/res/core/weapons/lance.xml
+++ b/res/core/weapons/lance.xml
@@ -1,7 +1,6 @@
-
-
diff --git a/res/core/weapons/mallornlance.xml b/res/core/weapons/mallornlance.xml
index 0186143e4..c67390d52 100644
--- a/res/core/weapons/mallornlance.xml
+++ b/res/core/weapons/mallornlance.xml
@@ -1,7 +1,6 @@
-
-
diff --git a/res/core/weapons/rustyaxe.xml b/res/core/weapons/rustyaxe.xml
index 2ff19570c..fea6b8642 100644
--- a/res/core/weapons/rustyaxe.xml
+++ b/res/core/weapons/rustyaxe.xml
@@ -1,7 +1,6 @@
-
-
diff --git a/res/core/weapons/rustyhalberd.xml b/res/core/weapons/rustyhalberd.xml
index c1b1f69a9..3f0bd93b7 100644
--- a/res/core/weapons/rustyhalberd.xml
+++ b/res/core/weapons/rustyhalberd.xml
@@ -1,7 +1,6 @@
-
-
diff --git a/res/e3a/armor/plate.xml b/res/e3a/armor/plate.xml
index 29cabbf1a..79391fbcb 100644
--- a/res/e3a/armor/plate.xml
+++ b/res/e3a/armor/plate.xml
@@ -1,7 +1,6 @@
-
-
-
+
-
diff --git a/res/e3a/armor/scale.xml b/res/e3a/armor/scale.xml
index 7039b4008..4d3e38e8a 100644
--- a/res/e3a/armor/scale.xml
+++ b/res/e3a/armor/scale.xml
@@ -1,9 +1,9 @@
-
-
-
+
+
+
-
-
diff --git a/res/e3a/armor/towershield.xml b/res/e3a/armor/towershield.xml
index e80c03523..aebbfc682 100644
--- a/res/e3a/armor/towershield.xml
+++ b/res/e3a/armor/towershield.xml
@@ -1,9 +1,9 @@
-
-
-
+
+
+
-
-
diff --git a/res/e3a/buildings.xml b/res/e3a/buildings.xml
index 9eeca952f..8641fd89e 100644
--- a/res/e3a/buildings.xml
+++ b/res/e3a/buildings.xml
@@ -3,16 +3,14 @@
-
-
-
-
+
+
-
+
-
+
diff --git a/res/e3a/items.xml b/res/e3a/items.xml
index 7d7e6b286..0399043e5 100644
--- a/res/e3a/items.xml
+++ b/res/e3a/items.xml
@@ -7,83 +7,72 @@
-
-
-
+
-
- -
-
+
-
- -
-
+
-
- -
-
+
-
- -
-
+
-
- -
-
+
-
- -
-
+
-
- -
-
+
-
- -
+
-
-
- -
-
-
+
diff --git a/res/e3a/races.xml b/res/e3a/races.xml
index 2e5a81aee..8b0cfae6d 100644
--- a/res/e3a/races.xml
+++ b/res/e3a/races.xml
@@ -71,7 +71,11 @@
-
+
@@ -116,7 +120,11 @@
-
+
@@ -156,7 +164,11 @@
-
+
diff --git a/res/e3a/resources/iron.xml b/res/e3a/resources/iron.xml
index 7ffe36f1e..55f63ca67 100644
--- a/res/e3a/resources/iron.xml
+++ b/res/e3a/resources/iron.xml
@@ -1,10 +1,9 @@
- -
-
-
-
+ -
+
+
+
-
diff --git a/res/e3a/resources/stone.xml b/res/e3a/resources/stone.xml
index dfb039093..d8fd08573 100644
--- a/res/e3a/resources/stone.xml
+++ b/res/e3a/resources/stone.xml
@@ -1,10 +1,8 @@
- -
-
-
-
+ -
+
+
-
diff --git a/res/e3a/spells.xml b/res/e3a/spells.xml
index 74eb89146..80d9e6260 100644
--- a/res/e3a/spells.xml
+++ b/res/e3a/spells.xml
@@ -10,14 +10,12 @@
-
-
@@ -39,7 +37,6 @@
-
@@ -106,7 +103,6 @@
-
@@ -119,7 +115,6 @@
-
@@ -189,7 +184,6 @@
-
@@ -205,7 +199,6 @@
-
@@ -269,7 +262,6 @@
-
@@ -304,12 +296,11 @@
-
+
-
@@ -394,21 +385,18 @@
-
-
-
@@ -416,7 +404,6 @@
-
@@ -426,7 +413,6 @@
-
@@ -435,7 +421,6 @@
-
@@ -444,7 +429,6 @@
-
@@ -454,7 +438,6 @@
-
@@ -472,39 +455,33 @@
-
-
-
-
-
-
@@ -518,7 +495,7 @@
-
+
diff --git a/res/e3a/strings.xml b/res/e3a/strings.xml
index 054cabfaa..e3c5b10ae 100644
--- a/res/e3a/strings.xml
+++ b/res/e3a/strings.xml
@@ -38,12 +38,6 @@
adamantium plates
-
-
- des dritten Zeitalters
- the third age
-
-
Packeis
fast ice
@@ -87,6 +81,7 @@
repeating crossbows
+
Gerüst
scaffolding
@@ -103,6 +98,7 @@
Wache
watch
+
Marktplatz
marketplace
@@ -210,7 +206,7 @@
Dieser Zauber wird die gesamte Ausrüstung der Zieleinheit für einige Zeit vor den Blicken anderer verschleiern. Der Zauber schützt nicht vor Dieben und Spionen.
This spell will hide the whole equipment of a target unit from the looks of others. It will not protect against thieves or spies.
-
+
Durch dieses uralte Tanzritual ruft der Zauberkundige die Kräfte des Lebens und der Fruchtbarkeit an. Die darauf folgenden Regenfälle begünstigen das Wachstum und erhöhen die Ernteerträge einiger Bauern der Region bis der Regen wieder nachlässt.
This ancient rite calls upon the forces of life and fertility. For the next few weeks, the peasants' harvest will be extraordinary good.
diff --git a/res/e3a/weapons.xml b/res/e3a/weapons.xml
index 052266a02..fdc8f1f3a 100644
--- a/res/e3a/weapons.xml
+++ b/res/e3a/weapons.xml
@@ -1,18 +1,18 @@
-
-
-
+
+
+
diff --git a/res/e3a/weapons/axe.xml b/res/e3a/weapons/axe.xml
new file mode 100644
index 000000000..6066c4cfc
--- /dev/null
+++ b/res/e3a/weapons/axe.xml
@@ -0,0 +1,13 @@
+
+
+ -
+
+
+
+
+
+
+
+
+
+
diff --git a/res/e3a/weapons/greatbow.xml b/res/e3a/weapons/greatbow.xml
index 7f08427c8..358a55f7d 100644
--- a/res/e3a/weapons/greatbow.xml
+++ b/res/e3a/weapons/greatbow.xml
@@ -4,10 +4,9 @@
* has lower damage
-->
- -
-
+
+
-
-
diff --git a/res/e3a/weapons/halberd.xml b/res/e3a/weapons/halberd.xml
index 2c11b62fc..c22e020b4 100644
--- a/res/e3a/weapons/halberd.xml
+++ b/res/e3a/weapons/halberd.xml
@@ -3,8 +3,7 @@
1. you cannt use this with cavalry
-->
-
-
-
+
-
diff --git a/res/e3a/weapons/lance.xml b/res/e3a/weapons/lance.xml
new file mode 100644
index 000000000..285862484
--- /dev/null
+++ b/res/e3a/weapons/lance.xml
@@ -0,0 +1,12 @@
+
+
+
-
+
+
+
+
+
+
+
+
+
diff --git a/res/e3a/weapons/mallornlance.xml b/res/e3a/weapons/mallornlance.xml
index 1fcad08c8..8eb25ceb4 100644
--- a/res/e3a/weapons/mallornlance.xml
+++ b/res/e3a/weapons/mallornlance.xml
@@ -1,7 +1,6 @@
- -
-
+
-
diff --git a/res/core/weapons/rep_crossbow.xml b/res/e3a/weapons/rep_crossbow.xml
similarity index 80%
rename from res/core/weapons/rep_crossbow.xml
rename to res/e3a/weapons/rep_crossbow.xml
index 66e3f9fc2..ffa1c0455 100644
--- a/res/core/weapons/rep_crossbow.xml
+++ b/res/e3a/weapons/rep_crossbow.xml
@@ -1,9 +1,8 @@
-
-
-
+
+
-
-
diff --git a/res/e3a/weapons/rustyhalberd.xml b/res/e3a/weapons/rustyhalberd.xml
index ed25d5db7..a53aec515 100644
--- a/res/e3a/weapons/rustyhalberd.xml
+++ b/res/e3a/weapons/rustyhalberd.xml
@@ -3,8 +3,7 @@
1. you cannot use this with cavalry
-->
-
-
-
+
-
diff --git a/res/eressea/artrewards.xml b/res/eressea/artrewards.xml
index 2a3c09950..b18fd5b20 100644
--- a/res/eressea/artrewards.xml
+++ b/res/eressea/artrewards.xml
@@ -3,16 +3,12 @@
-
-
-
-
+
- -
-
-
+
diff --git a/res/eressea/items.xml b/res/eressea/items.xml
index 69f84c890..3f5cc3d17 100644
--- a/res/eressea/items.xml
+++ b/res/eressea/items.xml
@@ -17,21 +17,15 @@
- -
-
-
+
- -
-
-
+
- -
-
-
+
@@ -44,52 +38,38 @@
- -
-
-
+
- -
-
-
+
- -
-
-
+
- -
-
-
+
- -
-
-
+
- -
-
-
+
- -
-
-
+
@@ -98,27 +78,13 @@
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
+
+
- -
-
-
+
diff --git a/res/eressea/races.xml b/res/eressea/races.xml
index 6deefacc9..986e2b85f 100644
--- a/res/eressea/races.xml
+++ b/res/eressea/races.xml
@@ -701,7 +701,7 @@
-
+
diff --git a/res/eressea/spells.xml b/res/eressea/spells.xml
index 1d762f4bd..6b2e43a15 100644
--- a/res/eressea/spells.xml
+++ b/res/eressea/spells.xml
@@ -10,14 +10,12 @@
-
-
@@ -494,12 +492,10 @@
-
-
@@ -507,7 +503,6 @@
-
@@ -520,12 +515,10 @@
-
-
@@ -533,18 +526,15 @@
-
-
-
@@ -558,12 +548,10 @@
-
-
@@ -583,25 +571,21 @@
-
-
-
-
@@ -609,7 +593,6 @@
-
@@ -617,20 +600,17 @@
-
-
-
diff --git a/res/eressea/strings.xml b/res/eressea/strings.xml
index f7497b810..8afeabbca 100644
--- a/res/eressea/strings.xml
+++ b/res/eressea/strings.xml
@@ -116,18 +116,6 @@
Eine Geburtstagstorte mit 10 Kerzen. Herzlichen Glückwunsch, Eressea!
A birthday cake with 10 candles. Happy Birthday, Eressea!
-
- Dieses Fluggerät aus der Schmiede der Zwerge von Celeband galt wie die
- 'Ebene der Herausforderung' seit Urzeiten als verschollen, ja man
- zweifelte seine Existenz an. Die Sage überliefert, das derjenige, der
- sie auf der Spitze des Turmes seiner Gesinnung benutzt, als einziger
- die 'Ebene der Herausforderungen' verlassen kann.
-
-
- Glückwunsch, mein Kind. Du bist im Besitz des mächtigsten
- Artefaktes Eresseas. Ein Fluch, sagt man, liege auf ihm, denn
- niemand hat es bisher lange sein Eigen genannt...
-
Kleines trockenes Dauergebäck, m od. s; - u. -es, - u. -e
@@ -374,29 +362,6 @@
-
-
- Auge des Dämon
- eye of the demon
- oeil du démon
-
-
- Augen des Dämon
- eyes of the demon
- oeil du démon
-
-
- Schwinge des Greifen
- wing of the gryphon
- aile du griffon
-
-
- Schwingen des Greifen
- wings of the gryphon
- ailes du griffon
-
-
-
Adamantium
adamantium
@@ -427,5 +392,14 @@
Adamantiumrüstungen
adamantium plates
-
+
+ Katzenamulett
+ amulet of the kitten
+ amulette du chaton
+
+
+ amulets of the kitten
+ Katzenamulette
+ amulettes du chaton
+
diff --git a/res/races.xml b/res/races.xml
deleted file mode 100644
index fcfc1742b..000000000
--- a/res/races.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/res/races/goblin-2.xml b/res/races/goblin-2.xml
deleted file mode 100644
index f26fa780e..000000000
--- a/res/races/goblin-2.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/res/races/goblin-3.xml b/res/races/goblin-3.xml
index 3fd594939..a65d4c99a 100644
--- a/res/races/goblin-3.xml
+++ b/res/races/goblin-3.xml
@@ -1,5 +1,5 @@
-
=0
- if r.morale>=0 then
- create_curse(mage, r, "blessedharvest", force, force*2, 50 * force)
- end
- end
- end
- return level
-end
diff --git a/scripts/eressea/frost.lua b/scripts/eressea/frost.lua
index 2c2df4dae..beeef68f6 100644
--- a/scripts/eressea/frost.lua
+++ b/scripts/eressea/frost.lua
@@ -1,11 +1,11 @@
local function is_winter(turn)
local season = get_season(turn)
- return season == "calendar::winter"
+ return season == "winter"
end
local function is_spring(turn)
local season = get_season(turn)
- return season == "calendar::spring"
+ return season == "spring"
end
local function freeze(r, chance)
diff --git a/scripts/eressea/ponnuki.lua b/scripts/eressea/ponnuki.lua
index 29f882ab5..1a5d1959e 100644
--- a/scripts/eressea/ponnuki.lua
+++ b/scripts/eressea/ponnuki.lua
@@ -38,6 +38,7 @@ function ponnuki.init()
u.name = "Ponnuki"
u.info = "Go, Ponnuki, Go!"
u.race_name = "Ritter von Go"
+ u.status = 5 -- FLIEHE
print(u:show())
end
else
diff --git a/scripts/eressea/resources.lua b/scripts/eressea/resources.lua
index 2829d00c7..fa6e1c4da 100644
--- a/scripts/eressea/resources.lua
+++ b/scripts/eressea/resources.lua
@@ -1,16 +1,5 @@
-- global functions used in items.xml
-if not item_canuse then
- -- define a default, everyone can use everything
- function item_canuse(u, iname)
- return true
- end
-end
-
-function peasant_getresource(u)
- return u.region:get_resource("peasant")
-end
-
function peasant_changeresource(u, delta)
local p = u.region:get_resource("peasant")
p = p + delta
@@ -21,10 +10,6 @@ function peasant_changeresource(u, delta)
return p
end
-function hp_getresource(u)
- return u.hp
-end
-
function hp_changeresource(u, delta)
local hp = u.hp + delta
diff --git a/scripts/eressea/xmasitems.lua b/scripts/eressea/xmasitems.lua
index a05e023b8..dffea2675 100644
--- a/scripts/eressea/xmasitems.lua
+++ b/scripts/eressea/xmasitems.lua
@@ -25,6 +25,7 @@ end
function use_stardust(u, amount)
local p = u.region:get_resource("peasant")
+ assert(p>0)
p = math.ceil(1.5 * p)
u.region:set_resource("peasant", p)
local msg = usepotion_message(u, "stardust")
@@ -86,7 +87,7 @@ local self = {}
function self.update()
local turn = get_turn()
local season = get_season(turn)
- if season == "calendar::winter" then
+ if season == "winter" then
eressea.log.debug("it is " .. season .. ", the christmas trees do their magic")
local msg = message.create("xmastree_effect")
for r in regions() do
@@ -102,7 +103,7 @@ function self.update()
end
else
local prevseason = get_season(turn-1)
- if prevseason == "calendar::winter" then
+ if prevseason == "winter" then
-- we celebrate knut and kick out the trees.
for r in regions() do
if r:get_key("xm06") then
diff --git a/scripts/run-tests-e2.lua b/scripts/run-tests-e2.lua
index 4a2b3e59e..27617592f 100644
--- a/scripts/run-tests-e2.lua
+++ b/scripts/run-tests-e2.lua
@@ -17,6 +17,7 @@ require 'eressea.path'
require 'tests.e2'
require 'lunit'
+rng.inject(0)
rules = require('eressea.' .. config.rules)
result = lunit.main()
return result.errors + result.failed
diff --git a/scripts/run-tests-e3.lua b/scripts/run-tests-e3.lua
index 47bcca60b..0aefb5d3a 100644
--- a/scripts/run-tests-e3.lua
+++ b/scripts/run-tests-e3.lua
@@ -17,6 +17,7 @@ require 'eressea.xmlconf'
require 'tests.e3'
require 'lunit'
+rng.inject(0)
eressea.settings.set("rules.alliances", "0")
rules = require('eressea.' .. config.rules)
result = lunit.main()
diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua
index a9dcf2468..936d2a79b 100644
--- a/scripts/tests/common.lua
+++ b/scripts/tests/common.lua
@@ -6,7 +6,7 @@ local function _test_create_ship(r)
end
local function create_faction(race)
- return faction.create(race .. '@eressea.de', race, "de")
+ return faction.create(race, race .. '@eressea.de', "de")
end
local function one_unit(r, f)
@@ -218,6 +218,9 @@ function test_gmtool()
local r1 = region.create(1, 0, "plain")
local r2 = region.create(1, 1, "plain")
local r3 = region.create(1, 2, "plain")
+ if not gmtool then
+ return
+ end
gmtool.open()
gmtool.select(r1, true)
gmtool.select_at(0, 1, true)
@@ -1033,6 +1036,37 @@ function test_recruit()
end
end
+function test_give_horses()
+ local r = region.create(0, 0, "plain")
+ local f = faction.create("human", "noreply@eressea.de", "de")
+ local u = unit.create(f, r, 1)
+
+ r:set_resource("horse", 0)
+ u:add_item("horse", 21)
+ u:add_item("dolphin", 10)
+ u:add_order("GIB 0 7 PFERD")
+ u:add_order("GIB 0 5 DELPHIN")
+ process_orders()
+ assert_equal(7, r:get_resource("horse"))
+ assert_equal(5, u:get_item("dolphin"))
+ assert_equal(14, u:get_item("horse"))
+end
+
+function test_give_silver()
+ local r = region.create(0, 0, "plain")
+ local f = faction.create("human", "noreply@eressea.de", "de")
+ local u = unit.create(f, r, 1)
+
+ r:set_resource("peasant", 0)
+ r:set_resource("money", 11)
+ u:clear_orders()
+ u:add_item("money", 20)
+ u:add_order("GIB 0 10 SILBER")
+ process_orders()
+ assert_equal(21, r:get_resource("money"))
+ assert_equal(10, u:get_item("money"))
+end
+
function test_give_horses()
local r = region.create(0, 0, "plain")
local f = create_faction('human')
diff --git a/scripts/tests/config.lua b/scripts/tests/config.lua
index e47b7f925..a83b64350 100644
--- a/scripts/tests/config.lua
+++ b/scripts/tests/config.lua
@@ -11,7 +11,7 @@ function test_read_race()
eressea.free_game()
assert_not_nil(eressea.config)
eressea.config.parse('{ "races": { "orc" : {}}}')
- f = faction.create("orc@example.com", "orc", "en")
+ f = faction.create("orc", "orc@example.com", "en")
assert_not_nil(f)
end
diff --git a/scripts/tests/e2/adamantium.lua b/scripts/tests/e2/adamantium.lua
index 8bbccdd19..de9a2312f 100644
--- a/scripts/tests/e2/adamantium.lua
+++ b/scripts/tests/e2/adamantium.lua
@@ -11,7 +11,7 @@ function setup()
end
local function create_faction(race)
- return faction.create(race .. '@eressea.de', race, "de")
+ return faction.create(race, race .. '@eressea.de', "de")
end
local function _test_create_adamantium()
diff --git a/scripts/tests/e2/buildings.lua b/scripts/tests/e2/buildings.lua
new file mode 100644
index 000000000..4797643e1
--- /dev/null
+++ b/scripts/tests/e2/buildings.lua
@@ -0,0 +1,53 @@
+require "lunit"
+
+module("tests.e2.buildings", package.seeall, lunit.testcase )
+
+function setup()
+ eressea.game.reset()
+ eressea.settings.set("rules.food.flags", "4")
+end
+
+function teardown()
+ eressea.settings.set("rules.food.flags", "0")
+end
+
+function test_castle_names()
+ local r = region.create(0, 0, "plain")
+ local b = building.create(r, "castle")
+
+ assert_equal("site", b:get_typename(1))
+ assert_equal("tradepost", b:get_typename(2))
+ assert_equal("tradepost", b:get_typename(9))
+ assert_equal("fortification", b:get_typename(10))
+ assert_equal("fortification", b:get_typename(49))
+ assert_equal("tower", b:get_typename(50))
+ assert_equal("tower", b:get_typename(249))
+ assert_equal("castle", b:get_typename(250))
+ assert_equal("castle", b:get_typename(1249))
+ assert_equal("fortress", b:get_typename(1250))
+ assert_equal("fortress", b:get_typename(6249))
+ assert_equal("citadel", b:get_typename(6250))
+end
+
+function test_build_castle_stages()
+ local r = region.create(0,0, "plain")
+ local f = faction.create("human")
+ local u = unit.create(f, r, 1000)
+ local b = building.create(r, "castle")
+
+ u:add_item("stone", 1000)
+
+ u:set_skill("building", 1)
+ u:clear_orders()
+
+ u:add_order("MACHE BURG " .. itoa36(b.id))
+ process_orders()
+ assert_equal(10, b.size)
+
+ u:set_skill("building", 3)
+ u:clear_orders()
+
+ u:add_order("MACHE BURG " .. itoa36(b.id))
+ process_orders()
+ assert_equal(250, b.size)
+end
diff --git a/scripts/tests/e2/destroy.lua b/scripts/tests/e2/destroy.lua
index 3f422c2e5..430ca301c 100644
--- a/scripts/tests/e2/destroy.lua
+++ b/scripts/tests/e2/destroy.lua
@@ -10,7 +10,7 @@ end
function disabled_test_dont_move_after_destroy()
local r1 = region.create(0, 0, "plain")
local r2 = region.create(1, 0, "plain")
- local f = faction.create("test@example.com", "human", "de")
+ local f = faction.create("human", "test@example.com", "de")
local u = unit.create(f, r1, 1)
u.building = building.create(u.region, "castle")
u:clear_orders()
@@ -26,8 +26,8 @@ end
function test_dont_destroy_after_attack()
local r1 = region.create(0, 0, "plain")
- local u = unit.create(faction.create("one@example.com", "human", "de"), r1, 10)
- local u2 = unit.create(faction.create("two@example.com", "human", "de"), r1, 1)
+ local u = unit.create(faction.create("human", "one@example.com", "de"), r1, 10)
+ local u2 = unit.create(faction.create("human", "two@example.com", "de"), r1, 1)
u.building = building.create(u.region, "castle")
u:clear_orders()
u:add_order("ATTACKIERE " .. itoa36(u2.id))
@@ -38,7 +38,7 @@ end
function test_destroy_is_long()
local r1 = region.create(0, 0, "plain")
- local u = unit.create(faction.create("one@example.com", "human", "de"), r1, 10)
+ local u = unit.create(faction.create("human", "one@example.com", "de"), r1, 10)
u.building = building.create(u.region, "castle")
u:clear_orders()
u:add_order("LERNE Unterhaltung")
diff --git a/scripts/tests/e2/e2features.lua b/scripts/tests/e2/e2features.lua
index 5b2caf61c..1a4047d63 100644
--- a/scripts/tests/e2/e2features.lua
+++ b/scripts/tests/e2/e2features.lua
@@ -11,14 +11,14 @@ function setup()
end
function test_calendar()
- assert_equal(get_season(1011), "calendar::winter")
- assert_equal(get_season(1012), "calendar::spring")
+ assert_equal("winter", get_season(1011))
+ assert_equal("spring", get_season(1012))
end
function test_herbalism()
-- OBS: herbalism is currently an E2-only skill
local r = region.create(0, 0, "plain")
- local f = faction.create("herbalism@eressea.de", "human", "de")
+ local f = faction.create("human", "herbalism@eressea.de", "de")
local u = unit.create(f, r, 1)
eressea.settings.set("rules.grow.formula", 0) -- plants do not grow
@@ -44,7 +44,7 @@ function test_dwarf_bonus()
r:set_resource("iron", 100)
local level = r:get_resourcelevel("iron")
assert_equal(1, level)
- local u = unit.create(faction.create('test@example.com', "dwarf"), r)
+ local u = unit.create(faction.create("dwarf"), r)
assert_equal("dwarf", u.faction.race)
assert_equal("dwarf", u.race)
u.faction.name = "Zwerge"
@@ -65,7 +65,7 @@ end
function test_build_harbour()
-- try to reproduce mantis bug 2221
local r = region.create(0, 0, "plain")
- local f = faction.create("harbour@eressea.de", "human", "de")
+ local f = faction.create("human", "harbour@eressea.de", "de")
local u = unit.create(f, r)
size = 30
u.number = 20
@@ -93,8 +93,8 @@ local function one_unit(r, f)
end
local function two_factions()
- local f1 = faction.create("one@eressea.de", "human", "de")
- local f2 = faction.create("two@eressea.de", "human", "de")
+ local f1 = faction.create("human", "one@eressea.de", "de")
+ local f2 = faction.create("human", "two@eressea.de", "de")
return f1, f2
end
@@ -105,7 +105,7 @@ end
function test_learn()
eressea.settings.set("study.random_progress", "0")
local r = region.create(0, 0, "plain")
- local f = faction.create("noreply@eressea.de", "human", "de")
+ local f = faction.create("human", "noreply@eressea.de", "de")
f.age = 20
local u = unit.create(f, r)
u:clear_orders()
@@ -124,7 +124,7 @@ end
function test_teach()
eressea.settings.set("study.random_progress", "0")
local r = region.create(0, 0, "plain")
- local f = faction.create("noreply@eressea.de", "human", "de")
+ local f = faction.create("human", "noreply@eressea.de", "de")
f.age = 20
local u = unit.create(f, r, 10)
local u2 = unit.create(f, r)
@@ -141,7 +141,7 @@ end
function test_rename()
local r = region.create(0, 0, "plain")
- local f = faction.create("noreply@eressea.de", "human", "de")
+ local f = faction.create("human", "noreply@eressea.de", "de")
local u = unit.create(f, r)
u:add_item("aoh", 1)
assert_equal(u:get_item("ao_healing"), 1)
@@ -149,7 +149,7 @@ end
function test_unit_limit_is_1500()
local r = region.create(0,0, "plain")
- local f = faction.create("noreply@eressea.de", "human", "de")
+ local f = faction.create("human", "noreply@eressea.de", "de")
for i = 1,1500 do
unit.create(f, r, 1)
end
@@ -165,7 +165,7 @@ function test_ship_capacity()
local r = region.create(0,0, "ocean")
region.create(1,0, "ocean")
local r2 = region.create(2,0, "ocean")
- local f = faction.create("capacity@eressea.de", "human", "de")
+ local f = faction.create("human", "capacity@eressea.de", "de")
-- u1 is at the limit and moves
local s1 = ship.create(r, "boat")
@@ -202,7 +202,7 @@ end
function test_levitate()
local r = region.create(0,0, "plain")
- local f = faction.create("noreply@eressea.de", "human", "de")
+ local f = faction.create("human", "noreply@eressea.de", "de")
local u = unit.create(f, r, 2)
local s = ship.create(r, "boat")
u.ship = s
@@ -228,15 +228,15 @@ end
function test_races()
local races = { "wolf", "orc", "human", "demon" }
for k,v in ipairs(races) do
- local f = faction.create("noreply@eressea.de", "human", "de")
+ local f = faction.create("human", "noreply@eressea.de", "de")
assert_not_equal(nil, f)
end
end
function test_can_give_person()
local r = region.create(0, 0, "plain")
- local f1 = faction.create("noreply@eressea.de", "human", "de")
- local f2 = faction.create("noreply@eressea.de", "human", "de")
+ local f1 = faction.create("human", "noreply@eressea.de", "de")
+ local f2 = faction.create("human", "noreply@eressea.de", "de")
local u1 = unit.create(f1, r, 10)
local u2 = unit.create(f2, r, 10)
u1.faction.age = 10
@@ -254,29 +254,10 @@ function test_can_give_person()
end
function test_no_uruk()
- local f1 = faction.create("noreply@eressea.de", "uruk", "de")
+ local f1 = faction.create("uruk")
assert_equal(f1.race, "orc")
end
-function test_snowman()
- local r = region.create(0, 0, "glacier")
- local f = faction.create("noreply@eressea.de", "human", "de")
- local u = unit.create(f, r, 1)
- u:add_item("snowman", 1)
- u:clear_orders()
- u:add_order("BENUTZEN 1 Schneemann")
- process_orders()
- for u2 in r.units do
- if u2.id~=u.id then
- assert_equal("snowman", u2.race)
- assert_equal(1000, u2.hp)
- u = nil
- break
- end
- end
- assert_equal(nil, u)
-end
-
function test_block_movement()
eressea.settings.set("rules.guard.base_stop_prob", "0.3")
eressea.settings.set("rules.guard.amulet_stop_prob", "0.0")
@@ -368,7 +349,7 @@ end
function test_stonegolems()
local r0 = region.create(0, 0, "plain")
- local f1 = faction.create("noreply@eressea.de", "stonegolem", "de")
+ local f1 = faction.create("stonegolem")
local u1 = unit.create(f1, r0, 1)
local u2 = unit.create(f1, r0, 2)
local c1 = building.create(r0, "castle")
@@ -397,7 +378,7 @@ end
function test_birthdaycake()
r = region.create(0,0, "plain")
- f = faction.create("cake@eressea.de", "human", "de")
+ f = faction.create("human")
u = unit.create(f, r, 1)
u:add_item("birthdaycake", 1)
u:clear_orders()
@@ -408,7 +389,7 @@ end
function test_demonstealth()
local desc, r, f, u
r = region.create(0, 0, "plain")
- f = faction.create("demon@eressea.de", "demon", "de")
+ f = faction.create("demon")
u = unit.create(f, r, 1)
u:clear_orders()
@@ -423,3 +404,7 @@ function test_demonstealth()
desc = u:show()
assert_equal(nil, string.find(desc, "Drache"))
end
+
+function test_calendar_season_2328()
+ assert_equal("fall", get_season(1026))
+end
diff --git a/scripts/tests/e2/guard.lua b/scripts/tests/e2/guard.lua
index 8e62a364d..e3cf8075f 100644
--- a/scripts/tests/e2/guard.lua
+++ b/scripts/tests/e2/guard.lua
@@ -11,7 +11,7 @@ end
function test_guard_unarmed()
local r1 = region.create(0, 0, "plain")
- local f1 = faction.create("hodor@eressea.de", "human", "de")
+ local f1 = faction.create("human", "hodor@eressea.de", "de")
local u1 = unit.create(f1, r1, 1)
assert_equal(false, u1.guard)
u1:clear_orders()
@@ -22,7 +22,7 @@ end
function test_guard_armed()
local r1 = region.create(0, 0, "plain")
- local f1 = faction.create("hodor@eressea.de", "human", "de")
+ local f1 = faction.create("human", "hodor@eressea.de", "de")
local u1 = unit.create(f1, r1, 1)
assert_equal(false, u1.guard)
u1:add_item("sword", 1)
@@ -36,10 +36,10 @@ end
function test_guard_allows_move_after_combat() -- bug 1493
local r1 = region.create(0, 0, "plain")
local r2 = region.create(1, 0, "plain")
- local f1 = faction.create("bernd@eressea.de", "human", "de")
+ local f1 = faction.create("human", "bernd@eressea.de", "de")
local u1 = unit.create(f1, r1, 10)
local uid1 = u1.id
- local f2 = faction.create("horst@eressea.de", "human", "de")
+ local f2 = faction.create("human", "horst@eressea.de", "de")
local u2 = unit.create(f2, r1, 1)
u1:add_order("BEWACHE")
u1:add_item("sword", 10)
@@ -59,10 +59,10 @@ end
function test_no_guard_no_move_after_combat() -- bug 1493
local r1 = region.create(0, 0, "plain")
local r2 = region.create(1, 0, "plain")
- local f1 = faction.create("bernd@eressea.de", "human", "de")
+ local f1 = faction.create("human", "bernd@eressea.de", "de")
local u1 = unit.create(f1, r1, 10)
local uid1 = u1.id
- local f2 = faction.create("horst@eressea.de", "human", "de")
+ local f2 = faction.create("human", "horst@eressea.de", "de")
local u2 = unit.create(f2, r1, 1)
u1:add_order("BEWACHE")
u1:add_item("sword", 10)
diff --git a/scripts/tests/e2/init.lua b/scripts/tests/e2/init.lua
index 991014287..7fbc0eb95 100644
--- a/scripts/tests/e2/init.lua
+++ b/scripts/tests/e2/init.lua
@@ -1,3 +1,6 @@
+require 'tests.e2.spells'
+require 'tests.e2.buildings'
+require 'tests.e2.production'
require 'tests.e2.adamantium'
require 'tests.e2.undead'
require 'tests.e2.shiplanding'
@@ -5,8 +8,9 @@ require 'tests.e2.e2features'
require 'tests.e2.movement'
require 'tests.e2.destroy'
require 'tests.e2.guard'
-require 'tests.e2.spells'
require 'tests.e2.stealth'
+require 'tests.e2.items'
+require 'tests.items'
require 'tests.economy'
require 'tests.orders'
require 'tests.common'
@@ -15,3 +19,5 @@ require 'tests.storage'
require 'tests.magicbag'
require 'tests.process'
require 'tests.xmas'
+require 'tests.production'
+require 'tests.spells'
diff --git a/scripts/tests/e2/items.lua b/scripts/tests/e2/items.lua
index 9bc747650..da7b3ae8f 100644
--- a/scripts/tests/e2/items.lua
+++ b/scripts/tests/e2/items.lua
@@ -11,9 +11,41 @@ function setup()
eressea.settings.set("magic.regeneration.enable", "0")
end
+function test_nestwarmth_insect()
+ local r = region.create(0, 0, "plain")
+ local f = faction.create("insect", "noreply@eressea.de", "de")
+ local u = unit.create(f, r, 1)
+ local flags = u.flags
+ u:add_item("nestwarmth", 2)
+ u:clear_orders()
+ u:add_order("BENUTZEN 1 Nestwaerme")
+ turn_begin()
+ turn_process()
+ assert_equal(flags+64, u.flags) -- UFL_WARMTH
+ assert_equal(1, u:get_item("nestwarmth"))
+ assert_equal(1, f:count_msg_type('usepotion'))
+ turn_end()
+end
+
+function test_nestwarmth_other()
+ local r = region.create(0, 0, "plain")
+ local f = faction.create("human", "noreply@eressea.de", "de")
+ local u = unit.create(f, r, 1)
+ local flags = u.flags
+ u:add_item("nestwarmth", 2)
+ u:clear_orders()
+ u:add_order("BENUTZEN 1 Nestwaerme")
+ turn_begin()
+ turn_process()
+ assert_equal(flags, u.flags) -- nothing happens
+ assert_equal(2, u:get_item("nestwarmth"))
+ assert_equal(1, f:count_msg_type('error163'))
+ turn_end()
+end
+
function test_meow()
local r = region.create(0, 0, "plain")
- local f = faction.create("noreply@eressea.de", "human", "de")
+ local f = faction.create("human", "noreply@eressea.de", "de")
local u = unit.create(f, r, 1)
u:add_item("aoc", 1)
u:clear_orders()
@@ -27,7 +59,7 @@ end
function test_aurapotion50()
local r = region.create(0, 0, "plain")
- local f = faction.create("noreply@eressea.de", "human", "de")
+ local f = faction.create("human", "noreply@eressea.de", "de")
local u = unit.create(f, r, 1)
u:add_item("aurapotion50", 1)
u:set_skill('magic', 10);
@@ -45,33 +77,45 @@ end
function test_bagpipe()
local r = region.create(0, 0, "plain")
- local f = faction.create("noreply@eressea.de", "human", "de")
+ local f = faction.create("human", "noreply@eressea.de", "de")
local u = unit.create(f, r, 1)
+ turn_begin()
u:add_item("bagpipeoffear", 1)
u:clear_orders()
u:add_order("BENUTZEN 1 Dudelsack")
- process_orders()
+ assert_equal(nil, r:get_curse('depression'))
+ turn_process()
+ assert_equal(0, r:get_curse('depression'))
assert_equal(1, u:get_item("bagpipeoffear"))
assert_equal(1, f:count_msg_type('bagpipeoffear_faction'))
assert_equal(1, r:count_msg_type('bagpipeoffear_region'))
+ turn_end()
+ -- duration is variable, but at least 4
+ assert_equal(0, r:get_curse('depression'))
end
function test_speedsail()
local r = region.create(0, 0, "plain")
- local f = faction.create("noreply@eressea.de", "human", "de")
+ local f = faction.create("human", "noreply@eressea.de", "de")
local u = unit.create(f, r, 1)
+
+ turn_begin()
u.ship = ship.create(r, "boat")
u:add_item("speedsail", 2)
u:clear_orders()
u:add_order("BENUTZEN 1 Sonnensegel")
- process_orders()
+ assert_equal(nil, u.ship:get_curse('shipspeed'))
+ turn_process()
+ assert_equal(1, u.ship:get_curse('shipspeed'))
assert_equal(1, u:get_item("speedsail"))
assert_equal(1, f:count_msg_type('use_speedsail'))
+ turn_end()
+ assert_equal(1, u.ship:get_curse('shipspeed')) -- effect stays forever
end
function test_foolpotion()
local r = region.create(0, 0, "plain")
- local f = faction.create("noreply@eressea.de", "human", "de")
+ local f = faction.create("human", "noreply@eressea.de", "de")
local u = unit.create(f, r, 1)
turn_begin()
u:add_item("p7", 1)
@@ -97,7 +141,7 @@ end
function test_snowman()
local r = region.create(0, 0, "glacier")
- local f = faction.create("noreply@eressea.de", "human", "de")
+ local f = faction.create("human", "noreply@eressea.de", "de")
local u = unit.create(f, r, 1)
u:add_item("snowman", 1)
u:clear_orders()
diff --git a/scripts/tests/e2/movement.lua b/scripts/tests/e2/movement.lua
index 390af2c48..b17d369f4 100644
--- a/scripts/tests/e2/movement.lua
+++ b/scripts/tests/e2/movement.lua
@@ -13,8 +13,8 @@ end
local r = region.create(0, 0, "plain")
local r2 = region.create(1, 0, "plain")
local r3 = region.create(-1, 0, "ocean")
- local f = faction.create("pirate@eressea.de", "human", "de")
- local f2 = faction.create("elf@eressea.de", "human", "de")
+ local f = faction.create("human", "pirate@eressea.de", "de")
+ local f2 = faction.create("human", "elf@eressea.de", "de")
local u1 = unit.create(f, r2, 1)
local u2 = unit.create(f2, r3, 1)
@@ -39,7 +39,7 @@ end
function test_dolphin_on_land()
local r1 = region.create(0, 0, "plain")
local r2 = region.create(1, 0, "plain")
- local f = faction.create("noreply@eressea.de", "human", "de")
+ local f = faction.create("human", "noreply@eressea.de", "de")
local u1 = unit.create(f, r1, 1)
u1.race = "dolphin"
u1:clear_orders()
@@ -51,7 +51,7 @@ end
function test_dolphin_to_land()
local r1 = region.create(0, 0, "ocean")
local r2 = region.create(1, 0, "plain")
- local f = faction.create("noreply@eressea.de", "human", "de")
+ local f = faction.create("human", "noreply@eressea.de", "de")
local u1 = unit.create(f, r1, 1)
u1.race = "dolphin"
u1:clear_orders()
@@ -63,7 +63,7 @@ end
function test_dolphin_in_ocean()
local r1 = region.create(0, 0, "ocean")
local r2 = region.create(1, 0, "ocean")
- local f = faction.create("noreply@eressea.de", "human", "de")
+ local f = faction.create("human", "noreply@eressea.de", "de")
local u1 = unit.create(f, r1, 1)
u1.race = "dolphin"
u1:clear_orders()
@@ -75,7 +75,7 @@ end
function test_follow()
local r1 = region.create(0, 0, "plain")
local r2 = region.create(1, 0, "plain")
- local f = faction.create("test@example.com", "human", "de")
+ local f = faction.create("human", "test@example.com", "de")
local u1 = unit.create(f, r1, 1)
local u2 = unit.create(f, r1, 1)
u1:clear_orders()
@@ -93,7 +93,7 @@ function test_follow_ship()
local r1 = region.create(0, 0, "plain")
region.create(1, 0, "ocean")
region.create(2, 0, "ocean")
- local f = faction.create("test@example.com", "human", "de")
+ local f = faction.create("human", "test@example.com", "de")
local u1 = unit.create(f, r1, 1)
local u2 = unit.create(f, r1, 1)
u1:add_item("money", 100)
diff --git a/scripts/tests/e2/production.lua b/scripts/tests/e2/production.lua
new file mode 100644
index 000000000..1d31011af
--- /dev/null
+++ b/scripts/tests/e2/production.lua
@@ -0,0 +1,78 @@
+require "lunit"
+
+module("tests.e2.production", package.seeall, lunit.testcase )
+
+function setup()
+ eressea.game.reset()
+ eressea.settings.set("rules.food.flags", "4") -- food is free
+ eressea.settings.set("NewbieImmunity", "0")
+end
+
+local function create_faction(race)
+ return faction.create(race, race .. '@example.com', "de")
+end
+
+function test_greatbow_needs_elf()
+-- only elves can build a greatbow
+ local r = region.create(0, 0, 'mountain')
+ local f = create_faction('human')
+ local u = unit.create(f, r, 1)
+
+ turn_begin()
+ u:set_skill('weaponsmithing', 5)
+ u:add_item('mallorn', 2)
+ u:add_order("MACHE Elfenbogen")
+ turn_process() -- humans cannot do it
+ assert_equal(1, f:count_msg_type("error117"))
+ assert_equal(0, u:get_item('greatbow'))
+ assert_equal(2, u:get_item('mallorn'))
+
+ u.race = 'elf'
+ turn_process() -- but elves can
+ assert_equal(1, u:get_item('greatbow'))
+ assert_equal(0, u:get_item('mallorn'))
+end
+
+function test_troll_quarrying_bonus()
+-- Von Trollen abgebaute Steine werden nur zu 75% vom "Regionsvorrat" abgezogen.
+-- Dieser Effekt ist kumulativ zu einem Steinbruch.
+ local r = region.create(0, 0, 'mountain')
+ local f = create_faction('human')
+ local u = unit.create(f, r, 1)
+
+ turn_begin()
+ r:set_resource("stone", 100)
+ u:set_skill('quarrying', 4)
+ u:add_order("MACHE Steine")
+ turn_process() -- humans get no bonus
+ assert_equal(4, u:get_item('stone'))
+ assert_equal(96, r:get_resource('stone'))
+
+ u.race = 'troll'
+ u:set_skill('quarrying', 2)
+ turn_process() -- trolls have +2 to quarrying, and save 25%
+ assert_equal(8, u:get_item('stone'))
+ assert_equal(93, r:get_resource('stone'))
+end
+
+function test_dwarf_mining_bonus()
+-- Von Zwergen abgebautes Eisen wird nur zu 60% vom "Regionsvorrat" abgezogen.
+-- Dieser Effekt ist kumulativ zu einem Bergwerk (siehe hier und hier).
+ local r = region.create(0, 0, 'mountain')
+ local f = create_faction('human')
+ local u = unit.create(f, r, 1)
+
+ turn_begin()
+ r:set_resource('iron', 100)
+ u:set_skill('mining', 10)
+ u:add_order('MACHE Eisen')
+ turn_process() -- humans get no bonus
+ assert_equal(10, u:get_item('iron'))
+ assert_equal(90, r:get_resource('iron'))
+
+ u.race = 'dwarf'
+ u:set_skill('mining', 8)
+ turn_process() -- dwarves have +2 to mining, and save 40%
+ assert_equal(20, u:get_item('iron'))
+ assert_equal(84, r:get_resource('iron'))
+end
diff --git a/scripts/tests/e2/shiplanding.lua b/scripts/tests/e2/shiplanding.lua
index a46a7da37..2258a1992 100644
--- a/scripts/tests/e2/shiplanding.lua
+++ b/scripts/tests/e2/shiplanding.lua
@@ -11,8 +11,8 @@ end
function test_landing1()
local ocean = region.create(1, 0, "ocean")
local r = region.create(0, 0, "plain")
- local f = faction.create("noreply@eressea.de", "human", "de")
- local f2 = faction.create("noreply@eressea.de", "human", "de")
+ local f = faction.create("human", "noreply@eressea.de", "de")
+ local f2 = faction.create("human", "noreply@eressea.de", "de")
local s = ship.create(ocean, "longboat")
local u1 = unit.create(f, ocean, 1)
local u2 = unit.create(f2, r, 1)
@@ -34,8 +34,8 @@ function test_landing_harbour_with_help()
local r = region.create(0, 0, "glacier")
local harbour = building.create(r, "harbour")
harbour.size = 25
- local f = faction.create("noreply@eressea.de", "human", "de")
- local f2 = faction.create("noreply@eressea.de", "human", "de")
+ local f = faction.create("human", "noreply@eressea.de", "de")
+ local f2 = faction.create("human", "noreply@eressea.de", "de")
local s = ship.create(ocean, "longboat")
local u1 = unit.create(f, ocean, 1)
local u2 = unit.create(f2, r, 1)
@@ -60,8 +60,8 @@ function test_landing_harbour_without_help()
local r = region.create(0, 0, "glacier")
local harbour = building.create(r, "harbour")
harbour.size = 25
- local f = faction.create("noreply@eressea.de", "human", "de")
- local f2 = faction.create("noreply@eressea.de", "human", "de")
+ local f = faction.create("human", "noreply@eressea.de", "de")
+ local f2 = faction.create("human", "noreply@eressea.de", "de")
local s = ship.create(ocean, "longboat")
local u1 = unit.create(f, ocean, 1)
local u2 = unit.create(f2, r, 1)
@@ -84,7 +84,7 @@ function test_landing_harbour_unpaid()
local r = region.create(0, 0, "glacier")
local harbour = building.create(r, "harbour")
harbour.size = 25
- local f = faction.create("noreply@eressea.de", "human", "de")
+ local f = faction.create("human", "noreply@eressea.de", "de")
local s = ship.create(ocean, "longboat")
local u1 = unit.create(f, ocean, 1)
local u2 = unit.create(f, r, 1)
@@ -104,8 +104,8 @@ end
function test_landing_terrain()
local ocean = region.create(1, 0, "ocean")
local r = region.create(0, 0, "glacier")
- local f = faction.create("noreply@eressea.de", "human", "de")
- local f2 = faction.create("noreply@eressea.de", "human", "de")
+ local f = faction.create("human", "noreply@eressea.de", "de")
+ local f2 = faction.create("human", "noreply@eressea.de", "de")
local s = ship.create(ocean, "longboat")
local u1 = unit.create(f, ocean, 1)
local u2 = unit.create(f2, r, 1)
@@ -126,8 +126,8 @@ function test_landing_insects()
local r = region.create(0, 0, "glacier")
local harbour = building.create(r, "harbour")
harbour.size = 25
- local f = faction.create("noreply@eressea.de", "insect", "de")
- local f2 = faction.create("noreply@eressea.de", "human", "de")
+ local f = faction.create("insect", "noreply@eressea.de", "de")
+ local f2 = faction.create("human", "noreply@eressea.de", "de")
local s = ship.create(ocean, "longboat")
local u1 = unit.create(f, ocean, 1)
local u2 = unit.create(f2, r, 1)
diff --git a/scripts/tests/e2/ships.lua b/scripts/tests/e2/ships.lua
index 151afc12c..351609a92 100644
--- a/scripts/tests/e2/ships.lua
+++ b/scripts/tests/e2/ships.lua
@@ -11,7 +11,7 @@ end
function test_ship_requires_skill()
local r1 = region.create(0, 0, "ocean")
local r2 = region.create(1, 0, "ocean")
- local f = faction.create("fake@eressea.de", "human", "de")
+ local f = faction.create("human", "fake@eressea.de", "de")
local u1 = unit.create(f, r1, 1)
u1.name = "fake"
u1.ship = ship.create(r1, "longboat")
@@ -25,7 +25,7 @@ end
function no_test_ship_happy_case()
local r1 = region.create(0, 0, "ocean")
local r2 = region.create(1, 0, "ocean")
- local f = faction.create("hodor@eressea.de", "human", "de")
+ local f = faction.create("human", "hodor@eressea.de", "de")
local u1 = unit.create(f, r1, 1)
local u2 = unit.create(f, r1, 1)
u1.ship = ship.create(r1, "longboat")
diff --git a/scripts/tests/e2/spells.lua b/scripts/tests/e2/spells.lua
index 6b1123a6f..fc1e3bc3b 100644
--- a/scripts/tests/e2/spells.lua
+++ b/scripts/tests/e2/spells.lua
@@ -8,11 +8,12 @@ function setup()
eressea.settings.set("nmr.timeout", "0")
eressea.settings.set("NewbieImmunity", "0")
eressea.settings.set("rules.food.flags", "4")
+ eressea.settings.set("rules.peasants.growth.factor", "0")
end
function test_shapeshift()
local r = region.create(42, 0, "plain")
- local f = faction.create("noreply@eressea.de", "demon", "de")
+ local f = faction.create("demon", "noreply@eressea.de", "de")
local u1 = unit.create(f, r, 1)
local u2 = unit.create(f, r, 1)
u1:clear_orders()
@@ -26,3 +27,78 @@ function test_shapeshift()
s = u2:show()
assert_equal("1 Goblin", string.sub(s, string.find(s, "1 Goblin")))
end
+
+function test_raindance()
+ local r = region.create(0, 0, "plain")
+ local f = faction.create("halfling", "noreply@eressea.de", "de")
+ local u = unit.create(f, r)
+ local err = 0
+ r:set_resource("peasant", 100)
+ r:set_resource("money", 0)
+ u.magic = "gwyrrd"
+ u.race = "dwarf"
+ u:set_skill("magic", 20)
+ u.aura = 200
+ err = err + u:add_spell("raindance")
+ assert_equal(0, err)
+
+ u:clear_orders()
+ u:add_order("ZAUBERE STUFE 1 Regentanz")
+ assert_equal(0, r:get_resource("money"))
+
+ process_orders()
+ assert_equal(200, r:get_resource("money"))
+ assert_equal(0, u:get_item("money"))
+
+ u:clear_orders()
+ u:add_order("ARBEITEN")
+ process_orders()
+ assert_equal(10, u:get_item("money")) -- only peasants benefit
+ assert_equal(400, r:get_resource("money"))
+ -- this is where the spell ends
+ process_orders()
+ process_orders()
+ assert_equal(600, r:get_resource("money"))
+end
+
+function test_earn_silver()
+ local r = region.create(0, 0, "mountain")
+ local f = faction.create("human")
+ local u = unit.create(f, r)
+
+ eressea.settings.set("rules.food.flags", "4")
+ eressea.settings.set("magic.fumble.enable", "0")
+ eressea.settings.set("rules.peasants.growth", "0")
+ eressea.settings.set("rules.economy.repopulate_maximum", "0")
+
+ u.magic = "gwyrrd"
+ u.race = "elf"
+ u:set_skill("magic", 10)
+ u.aura = 100
+ local err = u:add_spell("earn_silver#gwyrrd")
+ assert_equal(0, err)
+
+ u:clear_orders()
+ u:add_order("ZAUBERE STUFE 1 Viehheilung")
+ r:set_resource("money", 350)
+ r:set_resource("peasant", 0)
+ process_orders() -- get 50 silver
+ assert_equal(50, u:get_item("money"))
+ assert_equal(300, r:get_resource("money"))
+
+ u:clear_orders() -- get 100 silver
+ u:add_order("ZAUBERE STUFE 2 Viehheilung")
+ process_orders()
+ assert_equal(150, u:get_item("money"))
+ assert_equal(200, r:get_resource("money"))
+
+ u:clear_orders() -- get 150 silver
+ u:add_order("ZAUBERE STUFE 3 Viehheilung")
+ process_orders()
+ assert_equal(300, u:get_item("money"))
+ assert_equal(50, r:get_resource("money"))
+
+ process_orders() -- not enough
+ assert_equal(350, u:get_item("money"))
+ assert_equal(0, r:get_resource("money"))
+end
diff --git a/scripts/tests/e2/stealth.lua b/scripts/tests/e2/stealth.lua
index ab4320bb1..7f531776c 100644
--- a/scripts/tests/e2/stealth.lua
+++ b/scripts/tests/e2/stealth.lua
@@ -21,9 +21,9 @@ function setup()
set_rule('rules.food.flags', '4')
local r = region.create(0,0, "plain")
- f = faction.create("stealthy@eressea.de", "human", "de")
+ f = faction.create("human", "stealthy@eressea.de", "de")
u = unit.create(f, r, 1)
- f = faction.create("stealth@eressea.de", "human", "de")
+ f = faction.create("human", "stealth@eressea.de", "de")
unit.create(f, r, 1) -- TARNE PARTEI NUMMER must have a unit in the region
end
diff --git a/scripts/tests/e2/undead.lua b/scripts/tests/e2/undead.lua
index 9f3f67f13..71c14ac36 100644
--- a/scripts/tests/e2/undead.lua
+++ b/scripts/tests/e2/undead.lua
@@ -8,7 +8,7 @@ end
function test_undead_give_item()
local r1 = region.create(0, 0, "plain")
- local f1 = faction.create("hodor@eressea.de", "human", "de")
+ local f1 = faction.create("human", "hodor@eressea.de", "de")
local u1 = unit.create(f1, r1, 1)
u1.race = "undead"
u1:clear_orders()
@@ -20,7 +20,7 @@ end
function test_undead_dont_give_person()
local r1 = region.create(0, 0, "plain")
- local f1 = faction.create("hodor@eressea.de", "human", "de")
+ local f1 = faction.create("human", "hodor@eressea.de", "de")
local u1 = unit.create(f1, r1, 2)
u1.race = "undead"
u1:clear_orders()
diff --git a/scripts/tests/e3/castles.lua b/scripts/tests/e3/buildings.lua
similarity index 69%
rename from scripts/tests/e3/castles.lua
rename to scripts/tests/e3/buildings.lua
index b16019159..709e7df74 100644
--- a/scripts/tests/e3/castles.lua
+++ b/scripts/tests/e3/buildings.lua
@@ -1,6 +1,6 @@
require "lunit"
-module("tests.e3.castles", package.seeall, lunit.testcase )
+module("tests.e3.buildings", package.seeall, lunit.testcase )
function setup()
eressea.game.reset()
@@ -11,9 +11,26 @@ function teardown()
eressea.settings.set("rules.food.flags", "0")
end
+function test_castle_names()
+ local r = region.create(0, 0, "plain")
+ local b = building.create(r, "castle")
+
+ assert_equal("site", b:get_typename(1))
+ assert_equal("site", b:get_typename(9))
+ assert_equal("fortification", b:get_typename(10))
+ assert_equal("fortification", b:get_typename(49))
+ assert_equal("tower", b:get_typename(50))
+ assert_equal("tower", b:get_typename(249))
+ assert_equal("castle", b:get_typename(250))
+ assert_equal("castle", b:get_typename(1249))
+ assert_equal("fortress", b:get_typename(1250))
+ assert_equal("fortress", b:get_typename(6249))
+ assert_equal("citadel", b:get_typename(6250))
+end
+
function test_build_watch()
local r = region.create(0, 0, "plain")
- local f = faction.create("e3build@eressea.de", "human", "de")
+ local f = faction.create("human", "e3build@eressea.de", "de")
local u = unit.create(f, r, 1)
u.number = 20
@@ -33,7 +50,7 @@ function test_build_watch()
assert_equal(10, u.building.size)
end
-function test_watch()
+function test_watch_names()
local r = region.create(0, 0, "plain")
local b = building.create(r, "watch")
@@ -46,9 +63,9 @@ end
function test_small_castles()
local r = region.create(0, 0, "plain")
- local f1 = faction.create("noreply@eressea.de", "human", "de")
+ local f1 = faction.create("human", "noreply@eressea.de", "de")
local u1 = unit.create(f1, r, 1)
- local f2 = faction.create("noreply@eressea.de", "halfling", "de")
+ local f2 = faction.create("halfling", "noreply@eressea.de", "de")
local u2 = unit.create(f2, r, 1)
local b = building.create(r, "castle")
@@ -65,7 +82,7 @@ end
function test_build_normal()
local r = region.create(0, 0, "plain")
- local f = faction.create("noreply@eressea.de", "human", "de")
+ local f = faction.create("human", "noreply@eressea.de", "de")
local u = unit.create(f, r, 1)
u:clear_orders()
u:add_item("stone", 10)
@@ -78,7 +95,7 @@ end
function test_build_packice()
local r = region.create(0, 0, "packice")
- local f = faction.create("packice@eressea.de", "human", "de")
+ local f = faction.create("human", "packice@eressea.de", "de")
local u = unit.create(f, r, 1)
u:clear_orders()
u:add_item("stone", 10)
@@ -90,7 +107,7 @@ end
function test_build_castle_stages()
local r = region.create(0,0, "plain")
- local f = faction.create("castle@eressea.de", "human", "de")
+ local f = faction.create("human", "castle@eressea.de", "de")
local u = unit.create(f, r, 1000)
local b = building.create(r, "castle")
diff --git a/scripts/tests/e3/init.lua b/scripts/tests/e3/init.lua
index aa253157e..fc0586f89 100644
--- a/scripts/tests/e3/init.lua
+++ b/scripts/tests/e3/init.lua
@@ -1,13 +1,16 @@
-require 'tests.e3.production'
-require 'tests.e3.castles'
+require 'tests.e3.buildings'
require 'tests.e3.stealth'
require 'tests.e3.spells'
require 'tests.e3.rules'
require 'tests.e3.parser'
require 'tests.e3.morale'
+require 'tests.e3.items'
+require 'tests.e3.production'
+require 'tests.spells'
require 'tests.economy'
require 'tests.orders'
require 'tests.common'
--- require 'tests.report'
+require 'tests.items'
require 'tests.magicbag'
require 'tests.process'
+require 'tests.production'
diff --git a/scripts/tests/e3/items.lua b/scripts/tests/e3/items.lua
new file mode 100644
index 000000000..d3b857381
--- /dev/null
+++ b/scripts/tests/e3/items.lua
@@ -0,0 +1,76 @@
+require "lunit"
+
+module("tests.e3.items", package.seeall, lunit.testcase )
+
+function setup()
+ eressea.game.reset()
+ eressea.settings.set("rules.food.flags", "4") -- food is free
+ eressea.settings.set("NewbieImmunity", "0")
+end
+
+function test_give_horses()
+ local r = region.create(0, 0, "plain")
+ local f = faction.create("human", "noreply@eressea.de", "de")
+ local u = unit.create(f, r, 1)
+
+ r:set_resource("horse", 0)
+ u:add_item("charger", 20)
+ u:add_order("GIB 0 10 Streitross")
+ process_orders()
+ assert_equal(10, r:get_resource("horse"))
+ assert_equal(10, u:get_item("charger"))
+end
+
+function test_goblins()
+ local r = region.create(0, 0, "plain")
+ local f1 = faction.create("goblin", "goblin@eressea.de", "de")
+ local f2 = faction.create("dwarf", "dwarf@eressea.de", "de")
+ local f3 = faction.create("elf", "elf@eressea.de", "de")
+ local ud = unit.create(f1, r, 1)
+ local uh = unit.create(f1, r, 1)
+ uh.race = "halfling"
+ local u2 = unit.create(f2, r, 1)
+ local u3 = unit.create(f3, r, 1)
+
+ local restricted = {
+ "towershield", "rep_crossbow", "plate", "lance",
+ "mallornlance", "greatbow", "greataxe", "axe", "scale",
+ "plate", "halberd", "greatsword", "rustyhalberd"
+ }
+ for k, v in ipairs(restricted) do
+ ud:add_item(v, 1)
+ uh:add_item(v, 1)
+ u2:add_item(v, 1)
+ u3:add_item(v, 1)
+ end
+
+ uh:add_order("ATTACKIERE " .. itoa36(u2.id))
+ uh:add_order("ATTACKIERE " .. itoa36(u3.id))
+ ud:add_order("ATTACKIERE " .. itoa36(u2.id))
+ ud:add_order("ATTACKIERE " .. itoa36(u3.id))
+ process_orders()
+end
+
+function test_make_horse()
+ eressea.settings.set("rules.horses.growth", "0")
+ local r = region.create(0, 0, "plain")
+ local f = faction.create("human", "horses@eressea.de", "de")
+ local u = unit.create(f, r, 1)
+ u:set_skill("training", 4)
+ r:set_resource("horse", 100)
+ u:add_order("MACHE 1 PFERD")
+ process_orders()
+ assert_equal(1, u:get_item("horse"))
+ assert_equal(99, r:get_resource("horse"))
+
+ u:clear_orders()
+ u:add_order("MACHE 1 STREITROSS")
+ u:add_item("money", 200)
+ u:add_item("iron", 1)
+ process_orders()
+ assert_equal(1, u:get_item("charger"))
+ assert_equal(0, u:get_item("horse"))
+ assert_equal(0, u:get_item("iron"))
+ assert_equal(0, u:get_item("money"))
+ assert_equal(99, r:get_resource("horse"))
+end
diff --git a/scripts/tests/e3/morale.lua b/scripts/tests/e3/morale.lua
index c01fad186..1dd92a758 100644
--- a/scripts/tests/e3/morale.lua
+++ b/scripts/tests/e3/morale.lua
@@ -14,7 +14,7 @@ end
function test_when_owner_returns_morale_stays()
local r = region.create(0, 0, "plain")
assert_equal(1, r.morale)
- local f1 = faction.create("owner_returns@eressea.de", "human", "de")
+ local f1 = faction.create("human", "owner_returns@eressea.de", "de")
local u1 = unit.create(f1, r, 1)
u1:add_item("money", 10000)
local b = building.create(r, "castle")
@@ -38,13 +38,13 @@ end
function test_morale_alliance()
local r = region.create(0, 0, "plain")
assert_equal(1, r.morale)
- local f1 = faction.create("ma1@eressea.de", "human", "de")
+ local f1 = faction.create("human", "ma1@eressea.de", "de")
local u1 = unit.create(f1, r, 1)
u1:add_item("money", 10000)
- local f2 = faction.create("ma2@eressea.de", "human", "de")
+ local f2 = faction.create("human", "ma2@eressea.de", "de")
local u2 = unit.create(f2, r, 1)
u2:add_item("money", 10000)
- local f3 = faction.create("ma3@eressea.de", "human", "de")
+ local f3 = faction.create("human", "ma3@eressea.de", "de")
local u3 = unit.create(f3, r, 1)
u3:add_item("money", 10000)
@@ -95,9 +95,9 @@ end
function test_bigger_castle_empty()
local r = region.create(0, 0, "plain")
assert_equal(1, r.morale)
- local f1 = faction.create("small1@eressea.de", "human", "de")
+ local f1 = faction.create("human", "small1@eressea.de", "de")
local u1 = unit.create(f1, r, 1)
- local f2 = faction.create("small2@eressea.de", "human", "de")
+ local f2 = faction.create("human", "small2@eressea.de", "de")
local u2 = unit.create(f2, r, 1)
u1:add_item("money", 10000)
@@ -129,7 +129,7 @@ end
function test_morale_change()
local r = region.create(0, 0, "plain")
assert_equal(1, r.morale)
- local f1 = faction.create("mchange@eressea.de", "human", "de")
+ local f1 = faction.create("human", "mchange@eressea.de", "de")
local u1 = unit.create(f1, r, 1)
u1:add_item("money", 10000)
@@ -195,9 +195,9 @@ end
function test_morale_give_command()
local r = region.create(0, 0, "plain")
assert_equal(1, r.morale)
- local f1 = faction.create("mold1@eressea.de", "human", "de")
+ local f1 = faction.create("human", "mold1@eressea.de", "de")
local u1 = unit.create(f1, r, 1)
- local f2 = faction.create("mold2@eressea.de", "human", "de")
+ local f2 = faction.create("human", "mold2@eressea.de", "de")
local u2 = unit.create(f2, r, 1)
local b = building.create(r, "castle")
diff --git a/scripts/tests/e3/parser.lua b/scripts/tests/e3/parser.lua
index 9d957464d..a56f08f76 100644
--- a/scripts/tests/e3/parser.lua
+++ b/scripts/tests/e3/parser.lua
@@ -8,7 +8,7 @@ end
function test_set_status_en()
local r = region.create(0, 0, "plain")
- local f = faction.create("bug_1882@eressea.de", "human", "en")
+ local f = faction.create("human", "bug_1882@eressea.de", "en")
local u = unit.create(f, r, 1)
u.status = 1
u:clear_orders()
@@ -23,7 +23,7 @@ end
function test_set_status_de()
local r = region.create(0, 0, "plain")
- local f = faction.create("bug_1882@eressea.de", "human", "de")
+ local f = faction.create("human", "bug_1882@eressea.de", "de")
local u = unit.create(f, r, 1)
u.status = 1
u:clear_orders()
@@ -34,7 +34,7 @@ end
function test_breed_horses()
local r = region.create(0, 0, "plain")
- local f = faction.create("bug_1886@eressea.de", "human", "en")
+ local f = faction.create("human", "bug_1886@eressea.de", "en")
local u = unit.create(f, r, 1)
local b = building.create(r, "stables")
b.size = 10
diff --git a/scripts/tests/e3/production.lua b/scripts/tests/e3/production.lua
index 85fdeb638..3469b06c4 100644
--- a/scripts/tests/e3/production.lua
+++ b/scripts/tests/e3/production.lua
@@ -9,171 +9,129 @@ function setup()
end
local function create_faction(race)
- return faction.create(race .. '@eressea.de', race, "de")
+ return faction.create(race, race .. '@example.com', "de")
end
-function test_laen_needs_mine()
- -- some resources require a building
- -- i.e. you cannot create laen without a mine
- local r = region.create(0, 0, "mountain")
- local f = create_faction('human')
- local u = unit.create(f, r, 1)
-
- turn_begin()
- r:set_resource('laen', 100)
- u:add_order("MACHE Laen")
- u:set_skill('mining', 7)
- turn_process()
- assert_equal(0, u:get_item('laen'))
- assert_equal(100, r:get_resource('laen'))
- assert_equal(1, f:count_msg_type("error104")) -- requires building
-
- u.building = building.create(u.region, "mine")
- u.building.working = true
- u.building.size = 10
- turn_process()
- assert_equal(1, u:get_item('laen'))
- assert_equal(99, r:get_resource('laen'))
-
- turn_end()
-end
-
-function test_mine_laen_bonus()
- -- some buildings grant a bonus on the production skill
- -- i.e. a mine adds +1 to mining
+function test_greatbow_needs_elf()
+-- only elves can build a greatbow
local r = region.create(0, 0, 'mountain')
local f = create_faction('human')
local u = unit.create(f, r, 1)
turn_begin()
- r:set_resource('laen', 100)
- assert_equal(100, r:get_resource('laen'))
- u:add_order("MACHE Laen")
- u:set_skill('mining', 6)
- u.building = building.create(u.region, "mine")
- u.building.working = true
- u.building.size = 10
- u.number = 2
- turn_process() -- T6 is not enough for laen
- assert_equal(0, u:get_item('laen'))
- assert_equal(100, r:get_resource('laen'))
- assert_equal(1, f:count_msg_type("manufacture_skills"))
+ u:set_skill('weaponsmithing', 5)
+ u:add_item('mallorn', 2)
+ u:add_order("MACHE Elfenbogen")
+ turn_process() -- humans cannot do it
+ assert_equal(1, f:count_msg_type("error117"))
+ assert_equal(0, u:get_item('greatbow'))
+ assert_equal(2, u:get_item('mallorn'))
- u:set_skill('mining', 13)
- turn_process() -- T13 is enough, the +1 produces one extra Laen
- assert_equal(4, u:get_item('laen')) -- FAIL (3)
- assert_equal(96, r:get_resource('laen'))
-
- turn_end()
+ u.race = 'elf'
+ turn_process() -- but elves can
+ assert_equal(1, u:get_item('greatbow'))
+ assert_equal(0, u:get_item('mallorn'))
end
-function test_mine_iron_bonus()
- -- some buildings grant a bonus on the production skill
- -- i.e. a mine adds +1 to mining iron
- --
+function test_troll_no_quarrying_bonus()
+-- Trolle kriegen keinen Rohstoffbonus wie in E2
local r = region.create(0, 0, 'mountain')
- local f = create_faction('human')
+ local f = create_faction('troll')
+ local u = unit.create(f, r, 1)
+
+ turn_begin()
+ r:set_resource("stone", 100)
+ u:set_skill('quarrying', 2) -- +2 Rassenbonus
+ u:add_order("MACHE Steine")
+ turn_process()
+ assert_equal(4, u:get_item('stone'))
+ assert_equal(96, r:get_resource('stone'))
+end
+
+function test_dwarf_no_mining_bonus()
+-- E3: Zwerge verlieren den Eisenabbaubonus
+ local r = region.create(0, 0, 'mountain')
+ local f = create_faction('dwarf')
local u = unit.create(f, r, 1)
turn_begin()
r:set_resource('iron', 100)
- assert_equal(100, r:get_resource('iron'))
- u:add_order("MACHE Eisen")
- u:set_skill('mining', 1)
- u.building = building.create(u.region, "mine")
- u.building.working = false
- u.building.size = 10
- u.number = 2
- turn_process() -- iron can be made without a working mine
+ u:set_skill('mining', 8) -- +2 skill bonus
+ u:add_order('MACHE Eisen')
+ turn_process()
+ assert_equal(10, u:get_item('iron'))
+ assert_equal(90, r:get_resource('iron'))
+end
+
+function test_dwarf_towershield()
+-- Zwerge können als einzige Rasse Turmschilde, Schuppenpanzer
+-- und Repetierarmbrüste bauen.
+ local r = region.create(0, 0, 'plain')
+ local f = create_faction('human')
+ local u = unit.create(f, r, 1)
+
+ turn_begin()
+ u:set_skill('armorer', 4)
+ u:add_item('iron', 1)
+ u:add_order("MACHE Turmschild")
+ turn_process() -- humans cannot do it
+ assert_equal(1, f:count_msg_type("error117"))
+ assert_equal(0, u:get_item('towershield'))
+ assert_equal(1, u:get_item('iron'))
+
+ u.race = 'dwarf'
+ u:set_skill('armorer', 2) -- dwarf has bonus +2
+ turn_process() -- but dwarves can
+ assert_equal(1, u:get_item('towershield'))
+ assert_equal(0, u:get_item('iron'))
+
+end
+
+function test_dwarf_scale()
+-- Zwerge können als einzige Rasse Turmschilde, Schuppenpanzer
+-- und Repetierarmbrüste bauen.
+ local r = region.create(0, 0, 'plain')
+ local f = create_faction('human')
+ local u = unit.create(f, r, 1)
+
+ turn_begin()
+ u:set_skill('armorer', 5)
+ u:add_item('iron', 2)
+ u:add_order("MACHE Schuppenpanzer")
+ turn_process() -- humans cannot do it
+ assert_equal(1, f:count_msg_type("error117"))
+ assert_equal(0, u:get_item('scale'))
assert_equal(2, u:get_item('iron'))
- assert_equal(98, r:get_resource('iron'))
- u.building.working = true
- turn_process()
- assert_equal(6, u:get_item('iron'))
- assert_equal(96, r:get_resource('iron'))
-
- turn_end()
+ u.race = 'dwarf'
+ u:set_skill('armorer', 3) -- dwarf has bonus +2
+ turn_process() -- but dwarves can
+ assert_equal(1, u:get_item('scale'))
+ assert_equal(0, u:get_item('iron'))
end
-function test_quarry_bonus()
- -- a quarry grants +1 to quarrying, and saves 50% stone
- --
- local r = region.create(0, 0, 'mountain')
+function test_dwarf_rep_xbow()
+-- Zwerge können als einzige Rasse Turmschilde, Schuppenpanzer
+-- und Repetierarmbrüste bauen.
+ local r = region.create(0, 0, 'plain')
local f = create_faction('human')
local u = unit.create(f, r, 1)
turn_begin()
- r:set_resource('stone', 100)
- assert_equal(100, r:get_resource('stone'))
- u:add_order("MACHE Stein")
- u:set_skill('quarrying', 1)
- u.number = 2
- u.building = building.create(u.region, 'quarry')
- u.building.working = false
- u.building.size = 10
- turn_process()
- assert_equal(2, u:get_item('stone'))
- assert_equal(98, r:get_resource('stone'))
+ u:set_skill('weaponsmithing', 5)
+ u:add_item('iron', 1)
+ u:add_item('log', 1)
+ u:add_order("MACHE Repetierarmbrust")
+ turn_process() -- humans cannot do it
+ assert_equal(1, f:count_msg_type("error117"))
+ assert_equal(0, u:get_item('rep_crossbow'))
+ assert_equal(1, u:get_item('iron'))
+ assert_equal(1, u:get_item('log'))
- u.building.working = true
- turn_process()
- assert_equal(6, u:get_item('stone'))
- assert_equal(96, r:get_resource('stone'))
-
- turn_end()
-end
-
-function test_smithy_bonus_iron()
--- a smithy adds +1 to weaponsmithing, and saves 50% iron
- local r = region.create(0, 0, 'mountain')
- local f = create_faction('human')
- local u = unit.create(f, r, 1)
-
- turn_begin()
- u.building = building.create(u.region, 'smithy')
- u.building.working = false
- u.building.size = 10
- u:set_skill('weaponsmithing', 5) -- needs 3
- u:add_item('iron', 100)
- u:add_order("MACHE Schwert")
- turn_process() -- building disabled
- assert_equal(1, u:get_item('sword'))
- assert_equal(99, u:get_item('iron'))
-
- u.building.working = true
- turn_process() -- building active
- assert_equal(3, u:get_item('sword'))
- assert_equal(98, u:get_item('iron'))
-
- turn_end()
-end
-
-function test_smithy_bonus_mixed()
--- a smithy adds +1 to weaponsmithing, and saves 50% iron
--- it does not save any other resource, though.
- local r = region.create(0, 0, 'mountain')
- local f = create_faction('human')
- local u = unit.create(f, r, 1)
-
- turn_begin()
- u.building = building.create(u.region, 'smithy')
- u.building.working = false
- u.building.size = 10
- u:set_skill('weaponsmithing', 5) -- needs 3
- u:add_item('iron', 100)
- u:add_item('log', 100)
- u:add_order("MACHE Kriegsaxt")
- turn_process() -- building disabled
- assert_equal(1, u:get_item('axe'))
- assert_equal(99, u:get_item('iron'))
- assert_equal(99, u:get_item('log'))
-
- u.building.working = true
- turn_process() -- building active
- assert_equal(3, u:get_item('axe'))
- assert_equal(98, u:get_item('iron'))
- assert_equal(97, u:get_item('log'))
-
- turn_end()
+ u.race = 'dwarf'
+ u:set_skill('weaponsmithing', 3) -- dwarf has bonus +2
+ turn_process() -- but dwarves can
+ assert_equal(1, u:get_item('rep_crossbow'))
+ assert_equal(0, u:get_item('iron'))
+ assert_equal(0, u:get_item('log'))
end
diff --git a/scripts/tests/e3/rules.lua b/scripts/tests/e3/rules.lua
index 3a5cdadfa..7eb2f13a3 100644
--- a/scripts/tests/e3/rules.lua
+++ b/scripts/tests/e3/rules.lua
@@ -38,12 +38,12 @@ function teardown()
end
function test_calendar()
- assert_equal(get_season(396), "calendar::winter")
+ assert_equal("winter", get_season(396))
end
function disable_test_bug_1738_build_castle_e3()
local r = region.create(0, 0, "plain")
- local f = faction.create("bug_1738@eressea.de", "human", "de")
+ local f = faction.create("human", "bug_1738@eressea.de", "de")
local c = building.create(r, "castle")
c.size = 228
@@ -73,10 +73,10 @@ end
function disable_test_alliance()
local r = region.create(0, 0, "plain")
- local f1 = faction.create("noreply@eressea.de", "human", "de")
+ local f1 = faction.create("human", "noreply@eressea.de", "de")
local u1 = unit.create(f1, r, 1)
u1:add_item("money", u1.number * 100)
- local f2 = faction.create("info@eressea.de", "human", "de")
+ local f2 = faction.create("human", "info@eressea.de", "de")
local u2 = unit.create(f2, r, 1)
u2:add_item("money", u2.number * 100)
assert(f1.alliance==nil)
@@ -125,7 +125,7 @@ end
function test_no_stealth()
local r = region.create(0,0, "plain")
- local f = faction.create("noreply@eressea.de", "human", "de")
+ local f = faction.create("human", "noreply@eressea.de", "de")
local u = unit.create(f, r, 1)
u:set_skill("stealth", 1)
@@ -138,7 +138,7 @@ end
function test_no_teach()
local r = region.create(0,0, "plain")
- local f = faction.create("noreply@eressea.de", "human", "de")
+ local f = faction.create("human", "noreply@eressea.de", "de")
local u1 = unit.create(f, r, 1)
local u2 = unit.create(f, r, 1)
@@ -160,7 +160,7 @@ function test_seecast()
for i = 1,10 do
region.create(i, 0, "ocean")
end
- local f = faction.create("noreply@eressea.de", "human", "de")
+ local f = faction.create("human", "noreply@eressea.de", "de")
local s1 = ship.create(r, "cutter")
local u1 = unit.create(f, r, 2)
u1:set_skill("sailing", 3)
@@ -193,7 +193,7 @@ function test_fishing()
eressea.settings.set("rules.food.flags", "0")
local r = region.create(0,0, "ocean")
local r2 = region.create(1,0, "plain")
- local f = faction.create("noreply@eressea.de", "human", "de")
+ local f = faction.create("human", "noreply@eressea.de", "de")
local s1 = ship.create(r, "cutter")
local u1 = unit.create(f, r, 3)
u1.ship = s1
@@ -219,8 +219,8 @@ function test_ship_capacity()
local r = region.create(0,0, "ocean")
region.create(1,0, "ocean")
local r2 = region.create(2,0, "ocean")
- local f = faction.create("noreply@eressea.de", "human", "de")
- local f2 = faction.create("noreply@eressea.de", "goblin", "de")
+ local f = faction.create("human", "noreply@eressea.de", "de")
+ local f2 = faction.create("goblin", "noreply@eressea.de", "de")
-- u1 is at the limit and moves
local s1 = ship.create(r, "cutter")
@@ -273,9 +273,9 @@ end
function test_owners()
local r = region.create(0, 0, "plain")
- local f1 = faction.create("noreply@eressea.de", "human", "de")
+ local f1 = faction.create("human", "noreply@eressea.de", "de")
local u1 = unit.create(f1, r, 1)
- local f2 = faction.create("noreply@eressea.de", "human", "de")
+ local f2 = faction.create("human", "noreply@eressea.de", "de")
local u2 = unit.create(f2, r, 1)
local u3 = unit.create(f2, r, 1)
@@ -304,7 +304,7 @@ function test_taxes()
local r = region.create(0, 0, "plain")
r:set_resource("peasant", 1000)
r:set_resource("money", 5000)
- local f = faction.create("noreply@eressea.de", "human", "de")
+ local f = faction.create("human", "noreply@eressea.de", "de")
local u = unit.create(f, r, 1)
u:clear_orders()
u:add_order("LERNE Holzfaellen") -- do not work
@@ -320,7 +320,7 @@ end
function test_region_owner_cannot_leave_castle()
local r = region.create(0, 0, "plain")
- local f = faction.create("noreply@eressea.de", "human", "de")
+ local f = faction.create("human", "noreply@eressea.de", "de")
f.id = 42
local b1 = building.create(r, "castle")
b1.size = 10
@@ -366,7 +366,7 @@ function market_fixture()
b.size = 10
b.working = true
- local f = faction.create("market1@eressea.de", "human", "de")
+ local f = faction.create("human", "market1@eressea.de", "de")
f.id = 42
local u = unit.create(f, r, 1)
u.building = b
@@ -424,7 +424,7 @@ end
function test_multiple_markets()
local r, u1, b, herbnames, luxurynames, herbtable, luxurytable = market_fixture()
local r2 = get_region(1,0)
- local f = faction.create("multim@eressea.de", "human", "de")
+ local f = faction.create("human", "multim@eressea.de", "de")
local u2 = unit.create(f, r2, 1)
local b2 = building.create(r2, "market")
b2.size = 10
@@ -444,7 +444,7 @@ end
function test_market()
local r = region.create(0, 0, "plain")
- local f1 = faction.create("market2@eressea.de", "human", "de")
+ local f1 = faction.create("human", "market2@eressea.de", "de")
local u1 = unit.create(f1, r, 1)
local b = building.create(r, "market")
@@ -541,7 +541,7 @@ function test_market_gives_items()
r = get_region(0, 0)
local b = building.create(r, "market")
b.size = 10
- local f = faction.create("market0@eressea.de", "human", "de")
+ local f = faction.create("human", "market0@eressea.de", "de")
f.id = 42
local u = unit.create(f, r, 1)
u.building = b
@@ -559,7 +559,7 @@ end
function test_spells()
local r = region.create(0, 0, "plain")
- local f = faction.create("noreply@eressea.de", "human", "de")
+ local f = faction.create("human", "noreply@eressea.de", "de")
local u = unit.create(f, r, 1)
u.race = "elf"
u:clear_orders()
@@ -587,7 +587,7 @@ function test_spells()
end
function test_canoe_passes_through_land()
- local f = faction.create("noreply@eressea.de", "human", "de")
+ local f = faction.create("human", "noreply@eressea.de", "de")
local src = region.create(0, 0, "ocean")
local land = region.create(1, 0, "plain")
region.create(2, 0, "ocean")
@@ -610,8 +610,8 @@ end
function test_give_50_percent_of_money()
local r = region.create(0, 0, "plain")
- local u1 = unit.create(faction.create("noreply@eressea.de", "human", "de"), r, 1)
- local u2 = unit.create(faction.create("noreply@eressea.de", "orc", "de"), r, 1)
+ local u1 = unit.create(faction.create("human", "noreply@eressea.de", "de"), r, 1)
+ local u2 = unit.create(faction.create("orc", "noreply@eressea.de", "de"), r, 1)
u1.faction.age = 10
u2.faction.age = 10
u1:add_item("money", 500)
@@ -630,19 +630,15 @@ function test_give_50_percent_of_money()
u1:add_order("GIB " .. itoa36(u2.id) .. " 221 Silber")
u2:clear_orders()
u2:add_order("HELFEN " .. itoa36(u1.faction.id) .. " GIB")
- u2:add_item("horse", 100)
- u2:add_order("GIB 0 ALLES PFERD")
- local h = r:get_resource("horse")
process_orders()
- assert_true(r:get_resource("horse")>=h+100)
assert_equal(m1-221, u1:get_item("money"))
assert_equal(m2+110, u2:get_item("money"))
end
function test_give_100_percent_of_items()
r = region.create(0, 0, "plain")
- local u1 = unit.create(faction.create("noreply@eressea.de", "human", "de"), r, 1)
- local u2 = unit.create(faction.create("noreply@eressea.de", "orc", "de"), r, 1)
+ local u1 = unit.create(faction.create("human", "noreply@eressea.de", "de"), r, 1)
+ local u2 = unit.create(faction.create("orc", "noreply@eressea.de", "de"), r, 1)
u1.faction.age = 10
u2.faction.age = 10
u1:add_item("money", 500)
@@ -660,8 +656,8 @@ end
function test_cannot_give_person()
local r = region.create(0, 0, "plain")
- local f1 = faction.create("noreply@eressea.de", "human", "de")
- local f2 = faction.create("noreply@eressea.de", "human", "de")
+ local f1 = faction.create("human", "noreply@eressea.de", "de")
+ local f2 = faction.create("human", "noreply@eressea.de", "de")
local u1 = unit.create(f1, r, 10)
local u2 = unit.create(f2, r, 10)
u1.faction.age = 10
@@ -679,8 +675,8 @@ end
function test_cannot_give_unit()
local r = region.create(0, 0, "plain")
- local f1 = faction.create("noreply@eressea.de", "human", "de")
- local f2 = faction.create("noreply@eressea.de", "human", "de")
+ local f1 = faction.create("human", "noreply@eressea.de", "de")
+ local f2 = faction.create("human", "noreply@eressea.de", "de")
local u1 = unit.create(f1, r, 10)
local u2 = unit.create(f2, r, 10)
u1.faction.age = 10
@@ -698,9 +694,9 @@ end
function test_guard_by_owners()
-- http://bugs.eressea.de/view.php?id=1756
local r = region.create(0,0, "mountain")
- local f1 = faction.create("noreply@eressea.de", "human", "de")
+ local f1 = faction.create("human", "noreply@eressea.de", "de")
f1.age=20
- local f2 = faction.create("noreply@eressea.de", "human", "de")
+ local f2 = faction.create("human", "noreply@eressea.de", "de")
f2.age=20
local u1 = unit.create(f1, r, 1)
local b = building.create(r, "castle")
@@ -721,7 +717,7 @@ function test_guard_by_owners()
end
local function setup_packice(x, onfoot)
- local f = faction.create("noreply@eressea.de", "human", "de")
+ local f = faction.create("human", "noreply@eressea.de", "de")
local plain = region.create(0,0, "plain")
local ice = region.create(1,0, "packice")
local ocean = region.create(2,0, "ocean")
@@ -782,7 +778,7 @@ function test_cannot_walk_into_ocean()
end
function test_p2()
- local f = faction.create("noreply@eressea.de", "human", "de")
+ local f = faction.create("human", "noreply@eressea.de", "de")
local r = region.create(0, 0, "plain")
local u = unit.create(f, r, 1)
r:set_resource("tree", 0)
@@ -799,7 +795,7 @@ end
function test_p2_move()
-- http://bugs.eressea.de/view.php?id=1855
- local f = faction.create("noreply@eressea.de", "human", "de")
+ local f = faction.create("human", "noreply@eressea.de", "de")
local r = region.create(0, 0, "plain")
region.create(1, 0, "plain")
local u = unit.create(f, r, 1)
@@ -818,7 +814,7 @@ end
function test_golem_use_four_iron()
local r0 = region.create(0, 0, "plain")
- local f1 = faction.create("noreply@eressea.de", "halfling", "de")
+ local f1 = faction.create("halfling", "noreply@eressea.de", "de")
local u1 = unit.create(f1, r0, 3)
u1.race = "irongolem"
u1:set_skill("weaponsmithing", 1)
@@ -828,15 +824,15 @@ function test_golem_use_four_iron()
process_orders()
- assert_equal(2, u1.number)
assert_equal(4, u1:get_item("towershield"))
+ assert_equal(2, u1.number)
end
function test_silver_weight_stops_movement()
local r1 = region.create(1, 1, "plain")
local r2 = region.create(2, 1, "plain")
region.create(3, 1, "plain")
- local f1 = faction.create("noreply@eressea.de", "human", "de")
+ local f1 = faction.create("human", "noreply@eressea.de", "de")
local u1 = unit.create(f1, r1, 1)
u1:clear_orders()
u1:add_order("NACH OST")
@@ -853,7 +849,7 @@ function test_silver_weight_stops_ship()
local r1 = region.create(1, 1, "ocean")
local r2 = region.create(2, 1, "ocean")
region.create(3, 1, "ocean")
- local f1 = faction.create("noreply@eressea.de", "human", "de")
+ local f1 = faction.create("human", "noreply@eressea.de", "de")
local u1 = unit.create(f1, r1, 1)
u1:set_skill("sailing", 3)
local s1 = ship.create(r1, "canoe")
@@ -870,7 +866,7 @@ end
function test_building_owner_can_enter_ship()
local r1 = region.create(1, 2, "plain")
- local f1 = faction.create("noreply@eressea.de", "human", "de")
+ local f1 = faction.create("human", "noreply@eressea.de", "de")
local b1 = building.create(r1, "castle")
b1.size = 10
local s1 = ship.create(r1, "cutter")
@@ -893,7 +889,7 @@ end
function test_only_building_owner_can_set_not_paid()
local r = region.create(0, 0, "plain")
- local f = faction.create("noreply@eressea.de", "human", "de")
+ local f = faction.create("human", "noreply@eressea.de", "de")
local u1 = unit.create(f, r, 1)
local u2 = unit.create(f, r, 1)
local mine = building.create(r, "mine")
@@ -917,7 +913,7 @@ end
function test_spyreport_message()
local r1 = region.create(1, 2, "plain")
- local f1 = faction.create("noreply@eressea.de", "human", "de")
+ local f1 = faction.create("human", "noreply@eressea.de", "de")
local u1 = unit.create(f1, r1, 1)
local u2 = unit.create(f1, r1, 1)
msg = message.create("spyreport")
@@ -944,7 +940,7 @@ function test_bug2083()
r:set_resource("peasant", 2000)
r.luxury = "balm"
- local f = faction.create("2083@eressea.de", "human", "de")
+ local f = faction.create("human", "2083@eressea.de", "de")
local u = unit.create(f, r, 1)
u:set_skill("building", 8)
u:add_item("stone", 100)
@@ -971,7 +967,7 @@ function test_bug2083()
end
function test_no_uruk()
- local f1 = faction.create("noreply@eressea.de", "uruk", "de")
+ local f1 = faction.create("uruk", "noreply@eressea.de", "de")
assert_equal(f1.race, "orc")
end
@@ -979,7 +975,7 @@ function test_bug2187()
set_rule("rules.food.flags", "0")
local r = region.create(0,0,"plain")
- local f = faction.create("2187@eressea.de", "goblin", "de")
+ local f = faction.create("goblin", "2187@eressea.de", "de")
local u = unit.create(f, r, 1)
u.race = "demon"
u.hp = u.hp_max * u.number
diff --git a/scripts/tests/e3/spells-e2.lua b/scripts/tests/e3/spells-e2.lua
index bf3fa1d6c..f232b8a1a 100644
--- a/scripts/tests/e3/spells-e2.lua
+++ b/scripts/tests/e3/spells-e2.lua
@@ -11,7 +11,7 @@ function setup()
eressea.settings.set("rules.food.flags", "4")
r = region.create(0, 0, "plain")
- f = faction.create("spell_payment@eressea.de", "elf", "de")
+ f = faction.create("elf", "spell_payment@eressea.de", "de")
u = unit.create(f, r, 1)
u.magic = "gray"
u:set_skill("magic", 12)
diff --git a/scripts/tests/e3/spells.lua b/scripts/tests/e3/spells.lua
index f99e4687b..24f97c221 100644
--- a/scripts/tests/e3/spells.lua
+++ b/scripts/tests/e3/spells.lua
@@ -9,44 +9,37 @@ function setup()
eressea.settings.set("rules.peasants.growth", "0")
end
-function test_blessedharvest_lasts_n_turn()
+function test_raindance()
local r = region.create(0, 0, "plain")
- local f = faction.create("noreply@eressea.de", "halfling", "de")
+ local f = faction.create("halfling", "noreply@eressea.de", "de")
local u = unit.create(f, r)
- local err = 0
r:set_resource("peasant", 100)
r:set_resource("money", 0)
- u:add_item("money", 1000)
u.magic = "gwyrrd"
u.race = "dwarf"
u:set_skill("magic", 20)
u.aura = 200
- err = err + u:add_spell("raindance")
- err = err + u:add_spell("blessedharvest")
+ local err = u:add_spell("raindance")
assert_equal(0, err)
u:clear_orders()
u:add_order("ZAUBERE STUFE 3 Regentanz")
assert_equal(0, r:get_resource("money"), 0)
- local m = 0
- local p = 100
-
process_orders()
assert_equal(200, r:get_resource("money"))
u:clear_orders()
u:add_order("ARBEITEN")
process_orders()
process_orders()
+ assert_equal(500, r:get_resource("money"))
process_orders()
- assert_equal(800, r:get_resource("money"))
- process_orders()
- assert_equal(900, r:get_resource("money"))
+ assert_equal(600, r:get_resource("money"))
end
function test_magic()
local r = region.create(0, 0, "plain")
- local f = faction.create("noreply@eressea.de", "halfling", "de")
+ local f = faction.create("halfling", "noreply@eressea.de", "de")
local u = unit.create(f, r)
local b = building.create(r, "castle")
@@ -64,3 +57,46 @@ function test_magic()
-- there used to be a SEGFAULT when writing reports here:
-- write_reports()
end
+
+-- E3: earn 50 per every TWO levels of spell
+function test_earn_silver()
+ local r = region.create(0, 0, "mountain")
+ local f = faction.create("human")
+ local u = unit.create(f, r)
+
+ eressea.settings.set("rules.food.flags", "4")
+ eressea.settings.set("magic.fumble.enable", "0")
+ eressea.settings.set("rules.peasants.growth", "0")
+ eressea.settings.set("rules.economy.repopulate_maximum", "0")
+
+ u.magic = "gwyrrd"
+ u.race = "elf"
+ u:set_skill("magic", 10)
+ u.aura = 100
+ local err = u:add_spell("earn_silver#gwyrrd")
+ assert_equal(0, err)
+
+ u:clear_orders()
+ u:add_order("ZAUBERE STUFE 1 Viehheilung")
+ r:set_resource("money", 200)
+ r:set_resource("peasant", 0)
+ process_orders() -- get 50 silver
+ assert_equal(50, u:get_item("money"))
+ assert_equal(150, r:get_resource("money"))
+
+ u:clear_orders() -- get 50 silver
+ u:add_order("ZAUBERE STUFE 2 Viehheilung")
+ process_orders()
+ assert_equal(100, u:get_item("money"))
+ assert_equal(100, r:get_resource("money"))
+
+ u:clear_orders() -- get 75 silver
+ u:add_order("ZAUBERE STUFE 3 Viehheilung")
+ process_orders()
+ assert_equal(175, u:get_item("money"))
+ assert_equal(25, r:get_resource("money"))
+
+ process_orders() -- not enough
+ assert_equal(200, u:get_item("money"))
+ assert_equal(0, r:get_resource("money"))
+end
diff --git a/scripts/tests/e3/stealth.lua b/scripts/tests/e3/stealth.lua
index 38ca7d8ea..866eb4f14 100644
--- a/scripts/tests/e3/stealth.lua
+++ b/scripts/tests/e3/stealth.lua
@@ -10,9 +10,9 @@ function setup()
eressea.settings.set("rules.food.flags", "4")
local r = region.create(0,0, "plain")
- f = faction.create("stealth1@eressea.de", "human", "de")
+ f = faction.create("human", "stealth1@eressea.de", "de")
u = unit.create(f, r, 1)
- f = faction.create("stealth2@eressea.de", "human", "de")
+ f = faction.create("human", "stealth2@eressea.de", "de")
end
function test_stealth_faction_on()
diff --git a/scripts/tests/faction.lua b/scripts/tests/faction.lua
index 87a6b5100..c264f4596 100644
--- a/scripts/tests/faction.lua
+++ b/scripts/tests/faction.lua
@@ -12,7 +12,7 @@ function setup()
}]]
eressea.config.reset()
assert(eressea.config.parse(conf)==0)
- f = faction.create("faction@eressea.de", "human", "de")
+ f = faction.create("human", "faction@eressea.de", "de")
assert(f~=nil)
end
diff --git a/scripts/tests/items.lua b/scripts/tests/items.lua
index 48f466409..5c2093953 100644
--- a/scripts/tests/items.lua
+++ b/scripts/tests/items.lua
@@ -11,42 +11,59 @@ function setup()
eressea.settings.set("magic.regeneration.enable", "0")
end
-function test_mistletoe()
+function test_mistletoe_okay()
local r = region.create(0, 0, "plain")
- local f = faction.create("noreply@eressea.de", "human", "de")
+ local f = faction.create("human", "noreply@eressea.de", "de")
local u = unit.create(f, r, 1)
+ turn_begin()
u:add_item('mistletoe', 2)
u:clear_orders()
u:add_order("BENUTZEN 1 Mistelzweig")
- process_orders()
+ assert_false(u:has_attrib('fleechance'))
+ turn_process()
+ assert_true(u:has_attrib('fleechance'))
assert_equal(1, u:get_item('mistletoe'))
assert_equal(1, f:count_msg_type('use_item'))
+ turn_end()
+end
+
+function test_mistletoe_fail()
+ 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
- process_orders()
+ 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()
end
function test_dreameye()
local r = region.create(0, 0, "plain")
- local f = faction.create("noreply@eressea.de", "human", "de")
+ local f = faction.create("human", "noreply@eressea.de", "de")
local u = unit.create(f, r, 1)
u:add_item("dreameye", 2)
u:clear_orders()
u:add_order("BENUTZEN 1 Traumauge")
- assert_false(u:is_cursed('skillmod'))
+ assert_nil(u:get_curse('skillmod'))
turn_begin()
turn_process()
- assert_true(u:is_cursed('skillmod'))
+ assert_not_nil(u:get_curse('skillmod'))
assert_equal(1, u:get_item("dreameye"))
assert_equal(1, f:count_msg_type('use_tacticcrystal'))
turn_end()
- assert_false(u:is_cursed('skillmod'))
+ assert_nil(u:get_curse('skillmod'))
end
function test_manacrystal()
local r = region.create(0, 0, "plain")
- local f = faction.create("noreply@eressea.de", "human", "de")
+ local f = faction.create("human", "noreply@eressea.de", "de")
local u = unit.create(f, r, 1)
u:add_item("manacrystal", 2)
u:clear_orders()
@@ -64,7 +81,7 @@ end
function test_skillpotion()
local r = region.create(0, 0, "plain")
- local f = faction.create("noreply@eressea.de", "human", "de")
+ local f = faction.create("human", "noreply@eressea.de", "de")
local u = unit.create(f, r, 1)
u:add_item("skillpotion", 2)
u:clear_orders()
@@ -76,31 +93,43 @@ end
function test_studypotion()
local r = region.create(0, 0, "plain")
- local f = faction.create("noreply@eressea.de", "human", "de")
+ local f = faction.create("human", "noreply@eressea.de", "de")
local u = unit.create(f, r, 1)
+ turn_begin()
u:add_item("studypotion", 2)
u:clear_orders()
u:add_order("LERNE Unterhaltung")
u:add_order("BENUTZEN 1 Lerntrank")
- process_orders()
+ turn_process()
+ -- cannot sense the "learning" attribute, because study_cmd
+ -- removes it during processing :(
assert_equal(1, u:get_item("studypotion"))
+ turn_end()
end
function test_antimagic()
local r = region.create(0, 0, "plain")
- local f = faction.create("noreply@eressea.de", "human", "de")
+ local f = faction.create("human", "noreply@eressea.de", "de")
local u = unit.create(f, r, 1)
+
+ turn_begin()
u:add_item("antimagic", 2)
u:clear_orders()
u:add_order("BENUTZEN 1 Antimagiekristall")
- process_orders()
+ assert_equal(nil, r:get_curse('antimagiczone'))
+ turn_process()
+ assert_equal(5, r:get_curse('antimagiczone'))
assert_equal(1, r:count_msg_type('use_antimagiccrystal'))
assert_equal(1, u:get_item("antimagic"))
+ turn_end()
+ assert_equal(5, r:get_curse('antimagiczone')) -- haelt zwei wochen
+ turn_end() -- hack: age the curse again
+ assert_equal(nil, r:get_curse('antimagiczone'))
end
function test_ointment()
local r = region.create(0, 0, "plain")
- local f = faction.create("noreply@eressea.de", "human", "de")
+ local f = faction.create("human", "noreply@eressea.de", "de")
local u = unit.create(f, r, 1)
local hp = u.hp
u.hp = 1
@@ -115,7 +144,7 @@ end
function test_bloodpotion_demon()
local r = region.create(0, 0, "plain")
- local f = faction.create("noreply@eressea.de", "demon", "de")
+ local f = faction.create("demon", "noreply@eressea.de", "de")
local u = unit.create(f, r, 1)
u:add_item("peasantblood", 1)
u:clear_orders()
@@ -128,7 +157,7 @@ end
function test_bloodpotion_other()
local r = region.create(0, 0, "plain")
- local f = faction.create("noreply@eressea.de", "human", "de")
+ local f = faction.create("human", "noreply@eressea.de", "de")
local u = unit.create(f, r, 1)
u:add_item("peasantblood", 1)
u:clear_orders()
diff --git a/scripts/tests/laws.lua b/scripts/tests/laws.lua
index 6f41fc54b..3a724a440 100644
--- a/scripts/tests/laws.lua
+++ b/scripts/tests/laws.lua
@@ -16,6 +16,7 @@ function setup()
"attack" : "ATTACKIERE",
"maketemp" : "MACHETEMP",
"end" : "ENDE",
+ "use" : "BENUTZEN",
"recruit" : "REKRUTIERE"
}
},
@@ -30,8 +31,8 @@ end
function test_force_leave_on()
local r = region.create(0, 0, "plain")
- local f1 = faction.create("owner@eressea.de")
- local f2 = faction.create("guest@eressea.de")
+ local f1 = faction.create("human", "owner@eressea.de")
+ local f2 = faction.create("human", "guest@eressea.de")
local u1 = unit.create(f1, r, 1)
local u2 = unit.create(f2, r, 1)
local b1 = building.create(r, "castle")
@@ -45,8 +46,8 @@ end
function test_force_leave_off()
local r = region.create(0, 0, "plain")
- local f1 = faction.create("owner@eressea.de")
- local f2 = faction.create("guest@eressea.de")
+ local f1 = faction.create("human", "owner@eressea.de")
+ local f2 = faction.create("human", "guest@eressea.de")
local u1 = unit.create(f1, r, 1)
local u2 = unit.create(f2, r, 1)
local b1 = building.create(r, "castle")
@@ -60,7 +61,7 @@ end
function test_make_temp()
local r = region.create(0, 0, "plain")
- local f1 = faction.create("owner@eressea.de", "human", "de")
+ local f1 = faction.create("human", "owner@eressea.de", "de")
local u1 = unit.create(f1, r, 10)
local u, u2
@@ -86,8 +87,8 @@ end
function test_force_leave_postcombat()
local r = region.create(0, 0, "plain")
- local f1 = faction.create("owner@eressea.de", "human", "de")
- local f2 = faction.create("guest@eressea.de", "human", "de")
+ local f1 = faction.create("human", "owner@eressea.de", "de")
+ local f2 = faction.create("human", "guest@eressea.de", "de")
local u1 = unit.create(f1, r, 10)
local u2 = unit.create(f2, r, 10)
local u, u3
diff --git a/scripts/tests/magicbag.lua b/scripts/tests/magicbag.lua
index 4ca5e6ae5..b51925726 100644
--- a/scripts/tests/magicbag.lua
+++ b/scripts/tests/magicbag.lua
@@ -6,7 +6,7 @@ local u
function setup()
eressea.free_game()
- u = unit.create(faction.create("test@example.com", "human", "de"), region.create(0, 0, "plain"), 1)
+ u = unit.create(faction.create("human", "test@example.com", "de"), region.create(0, 0, "plain"), 1)
end
function test_magicbag_weight()
diff --git a/scripts/tests/movement.lua b/scripts/tests/movement.lua
index 110b5b2a2..22bd8d30e 100644
--- a/scripts/tests/movement.lua
+++ b/scripts/tests/movement.lua
@@ -48,7 +48,7 @@ end
function test_walk_to_land()
local r1 = region.create(0, 0, "plain")
local r2 = region.create(1, 0, "plain")
- local f = faction.create("walk@example.com", "human", "de")
+ local f = faction.create("human", "walk@example.com", "de")
local u = unit.create(f, r1, 1)
u:add_order("NACH O")
process_orders()
@@ -58,7 +58,7 @@ end
function test_walk_into_ocean_fails()
local r1 = region.create(0, 0, "plain")
local r2 = region.create(1, 0, "ocean")
- local f = faction.create("test@example.com", "human", "de")
+ local f = faction.create("human", "test@example.com", "de")
local u = unit.create(f, r1, 1)
u:add_order("NACH O")
process_orders()
@@ -69,7 +69,7 @@ function test_walk_distance()
local r1 = region.create(0, 0, "plain")
local r2 = region.create(1, 0, "plain")
region.create(2, 0, "plain")
- local f = faction.create("test@example.com", "human", "de")
+ local f = faction.create("human", "test@example.com", "de")
local u = unit.create(f, r1, 1)
u:add_order("NACH O O")
process_orders()
@@ -81,7 +81,7 @@ function test_ride_max_distance()
local r2 = region.create(2, 0, "plain")
region.create(1, 0, "plain")
region.create(3, 0, "plain")
- local f = faction.create("test@example.com", "human", "de")
+ local f = faction.create("human", "test@example.com", "de")
local u = unit.create(f, r1, 1)
u:add_item("horse", 1)
u:set_skill("riding", 2)
@@ -94,7 +94,7 @@ function test_ride_over_capacity_leads_horse()
local r1 = region.create(0, 0, "plain")
local r2 = region.create(1, 0, "plain")
region.create(2, 0, "plain")
- local f = faction.create("test@example.com", "human", "de")
+ local f = faction.create("human", "test@example.com", "de")
local u = unit.create(f, r1, 3)
u:add_item("horse", 1)
u:set_skill("riding", 2)
@@ -107,7 +107,7 @@ function test_ride_no_skill_leads_horse()
local r1 = region.create(0, 0, "plain")
local r2 = region.create(1, 0, "plain")
region.create(2, 0, "plain")
- local f = faction.create("test@example.com", "human", "de")
+ local f = faction.create("human", "test@example.com", "de")
local u = unit.create(f, r1, 1)
u:add_item("horse", 1)
u:add_order("NACH O O")
diff --git a/scripts/tests/orders.lua b/scripts/tests/orders.lua
index dde9508e9..af0919640 100644
--- a/scripts/tests/orders.lua
+++ b/scripts/tests/orders.lua
@@ -12,7 +12,7 @@ local r, f, u
function setup()
eressea.free_game()
r = _G.region.create(0, 0, "mountain")
- f = _G.faction.create("noreply@eressea.de", "human", "de")
+ f = _G.faction.create("human", "noreply@eressea.de", "de")
u = _G.unit.create(f, r, 1)
u:clear_orders()
eressea.settings.set("rules.food.flags", "4")
@@ -20,6 +20,18 @@ function setup()
eressea.settings.set("NewbieImmunity", "0")
end
+function test_no_errors()
+ turn_begin()
+ u:add_order("!BENUTZEN 23 Yanxspirit")
+ turn_process()
+ assert_equal(0, f:count_msg_type('error43'))
+ u:clear_orders()
+ u:add_order("BENUTZEN 23 Yanxspirit")
+ turn_process()
+ assert_equal(1, f:count_msg_type('error43'))
+ turn_end()
+end
+
function test_learn()
u:add_order("LERNEN Hiebwaffen")
_G.process_orders()
diff --git a/scripts/tests/pool.lua b/scripts/tests/pool.lua
index d9b336919..0d24f8129 100644
--- a/scripts/tests/pool.lua
+++ b/scripts/tests/pool.lua
@@ -33,7 +33,7 @@ end
function test_give_nopool()
local r = region.create(1, 1, "plain")
- local f = faction.create("test@example.com", "human", "de")
+ local f = faction.create("human", "test@example.com", "de")
local u1 = unit.create(f, r, 1)
local u2 = unit.create(f, r, 1)
u1:add_item("money", 100)
@@ -45,7 +45,7 @@ end
function test_give_from_faction()
local r = region.create(1, 1, "plain")
- local f = faction.create("test@example.com", "human", "de")
+ local f = faction.create("human", "test@example.com", "de")
local u1 = unit.create(f, r, 1)
local u2 = unit.create(f, r, 1)
local u3 = unit.create(f, r, 1)
@@ -62,8 +62,8 @@ function test_give_divisor()
eressea.settings.set("rules.items.give_divisor", 2)
eressea.settings.set("GiveRestriction", 0)
local r = region.create(1, 1, "plain")
- local f1 = faction.create("test@example.com", "human", "de")
- local f2 = faction.create("test@example.com", "human", "de")
+ local f1 = faction.create("human", "test@example.com", "de")
+ local f2 = faction.create("human", "test@example.com", "de")
local u1 = unit.create(f1, r, 1)
local u2 = unit.create(f2, r, 1)
u2:add_order("KONTAKTIERE " .. itoa36(u1.id))
diff --git a/scripts/tests/process.lua b/scripts/tests/process.lua
index 3256c73e6..c5515be0b 100644
--- a/scripts/tests/process.lua
+++ b/scripts/tests/process.lua
@@ -7,7 +7,7 @@ local u, r, f,turn
function setup()
eressea.free_game()
r = region.create(0, 0, "plain")
- f = faction.create("bernd@eressea.de", "human", "de")
+ f = faction.create("human", "bernd@eressea.de", "de")
u = unit.create(f, r, 1)
u:add_item("money", 10)
turn = get_turn()
diff --git a/scripts/tests/production.lua b/scripts/tests/production.lua
new file mode 100644
index 000000000..c8a299676
--- /dev/null
+++ b/scripts/tests/production.lua
@@ -0,0 +1,207 @@
+require "lunit"
+
+module("tests.production", package.seeall, lunit.testcase )
+
+function setup()
+ eressea.game.reset()
+ eressea.settings.set("rules.food.flags", "4") -- food is free
+ eressea.settings.set("NewbieImmunity", "0")
+ eressea.settings.set("study.random_progress", "0")
+end
+
+local function create_faction(race)
+ return faction.create(race, race .. '@eressea.de', "de")
+end
+
+function test_laen_needs_mine()
+ -- some resources require a building
+ -- i.e. you cannot create laen without a mine
+ local r = region.create(0, 0, "mountain")
+ local f = create_faction('human')
+ local u = unit.create(f, r, 1)
+
+ turn_begin()
+ r:set_resource('laen', 100)
+ u:add_order("MACHE Laen")
+ u:set_skill('mining', 7)
+ turn_process()
+ assert_equal(0, u:get_item('laen'))
+ assert_equal(100, r:get_resource('laen'))
+ assert_equal(1, f:count_msg_type("building_needed")) -- requires building
+
+ u.building = building.create(u.region, "mine")
+ u.building.working = true
+ u.building.size = 10
+ turn_process()
+ assert_equal(1, u:get_item('laen'))
+ assert_equal(99, r:get_resource('laen'))
+
+ turn_end()
+end
+
+function test_mine_laen_bonus()
+ -- some buildings grant a bonus on the production skill
+ -- i.e. a mine adds +1 to mining
+ local r = region.create(0, 0, 'mountain')
+ local f = create_faction('human')
+ local u = unit.create(f, r, 1)
+
+ turn_begin()
+ r:set_resource('laen', 100)
+ assert_equal(100, r:get_resource('laen'))
+ u:add_order("MACHE Laen")
+ u:set_skill('mining', 6)
+ u.building = building.create(u.region, "mine")
+ u.building.working = true
+ u.building.size = 10
+ u.number = 2
+ turn_process() -- T6 is not enough for laen
+ assert_equal(0, u:get_item('laen'))
+ assert_equal(100, r:get_resource('laen'))
+ assert_equal(1, f:count_msg_type("manufacture_skills"))
+
+ u:set_skill('mining', 13)
+ turn_process() -- T13 is enough, the +1 produces one extra Laen
+ assert_equal(4, u:get_item('laen')) -- FAIL (3)
+ assert_equal(96, r:get_resource('laen'))
+
+ turn_end()
+end
+
+function test_mine_iron_bonus()
+ -- some buildings grant a bonus on the production skill
+ -- i.e. a mine adds +1 to mining iron
+ --
+ local r = region.create(0, 0, 'mountain')
+ local f = create_faction('human')
+ local u = unit.create(f, r, 1)
+
+ turn_begin()
+ r:set_resource('iron', 100)
+ assert_equal(100, r:get_resource('iron'))
+ u:add_order("MACHE Eisen")
+ u:set_skill('mining', 1)
+ u.building = building.create(u.region, "mine")
+ u.building.working = false
+ u.building.size = 10
+ u.number = 2
+ turn_process() -- iron can be made without a working mine
+ assert_equal(2, u:get_item('iron'))
+ assert_equal(98, r:get_resource('iron'))
+
+ u.building.working = true
+ turn_process()
+ assert_equal(6, u:get_item('iron'))
+ assert_equal(96, r:get_resource('iron'))
+
+ turn_end()
+end
+
+function test_quarry_bonus()
+ -- a quarry grants +1 to quarrying, and saves 50% stone
+ --
+ local r = region.create(0, 0, 'mountain')
+ local f = create_faction('human')
+ local u = unit.create(f, r, 1)
+
+ turn_begin()
+ r:set_resource('stone', 100)
+ assert_equal(100, r:get_resource('stone'))
+ u:add_order("MACHE Stein")
+ u:set_skill('quarrying', 1)
+ u.number = 2
+ u.building = building.create(u.region, 'quarry')
+ u.building.working = false
+ u.building.size = 10
+ turn_process()
+ assert_equal(2, u:get_item('stone'))
+ assert_equal(98, r:get_resource('stone'))
+
+ u.building.working = true
+ turn_process()
+ assert_equal(6, u:get_item('stone'))
+ assert_equal(96, r:get_resource('stone'))
+
+ turn_end()
+end
+
+function test_smithy_no_bonus()
+-- a smithy does not give a bonus to other skills
+-- five cartmakers make 5 carts, no matter what
+ local r = region.create(0, 0, 'mountain')
+ local f = create_faction('human')
+ local u = unit.create(f, r, 1)
+
+ turn_begin()
+ u.building = building.create(u.region, 'smithy')
+ u.building.working = false
+ u.building.size = 10
+ u.number = 5
+ u:set_skill('cartmaking', 1) -- needs 1 min
+ u:add_item('log', 100)
+ u:add_order("MACHE Wagen")
+ turn_process() -- building disabled
+ assert_equal(5, u:get_item('cart'))
+ assert_equal(75, u:get_item('log'))
+
+ u.building.working = true
+ turn_process() -- building active
+ assert_equal(10, u:get_item('cart'))
+ assert_equal(50, u:get_item('log'))
+
+ turn_end()
+end
+
+function test_smithy_bonus_iron()
+-- a smithy adds +1 to weaponsmithing, and saves 50% iron
+ local r = region.create(0, 0, 'mountain')
+ local f = create_faction('human')
+ local u = unit.create(f, r, 1)
+
+ turn_begin()
+ u.building = building.create(u.region, 'smithy')
+ u.building.working = false
+ u.building.size = 10
+ u:set_skill('weaponsmithing', 5) -- needs 3
+ u:add_item('iron', 100)
+ u:add_order("MACHE Schwert")
+ turn_process() -- building disabled
+ assert_equal(1, u:get_item('sword'))
+ assert_equal(99, u:get_item('iron'))
+
+ u.building.working = true
+ turn_process() -- building active
+ assert_equal(3, u:get_item('sword'))
+ assert_equal(98, u:get_item('iron'))
+
+ turn_end()
+end
+
+function test_smithy_bonus_mixed()
+-- a smithy adds +1 to weaponsmithing, and saves 50% iron
+-- it does not save any other resource, though.
+ local r = region.create(0, 0, 'mountain')
+ local f = create_faction('human')
+ local u = unit.create(f, r, 1)
+
+ turn_begin()
+ u.building = building.create(u.region, 'smithy')
+ u.building.working = false
+ u.building.size = 10
+ u:set_skill('weaponsmithing', 5) -- needs 3
+ u:add_item('iron', 100)
+ u:add_item('log', 100)
+ u:add_order("MACHE Kriegsaxt")
+ turn_process() -- building disabled
+ assert_equal(1, u:get_item('axe'))
+ assert_equal(99, u:get_item('iron'))
+ assert_equal(99, u:get_item('log'))
+
+ u.building.working = true
+ turn_process() -- building active
+ assert_equal(3, u:get_item('axe'))
+ assert_equal(98, u:get_item('iron'))
+ assert_equal(97, u:get_item('log'))
+
+ turn_end()
+end
diff --git a/scripts/tests/report.lua b/scripts/tests/report.lua
index 2a037c770..12d1538c3 100644
--- a/scripts/tests/report.lua
+++ b/scripts/tests/report.lua
@@ -36,7 +36,7 @@ end
function test_coordinates_unnamed_plane()
local p = plane.create(0, -3, -3, 7, 7)
local r = region.create(0, 0, "mountain")
- local f = faction.create("unnamed@eressea.de", "human", "de")
+ local f = faction.create("human", "unnamed@eressea.de", "de")
local u = unit.create(f, r, 1)
init_reports()
write_report(f)
@@ -46,7 +46,7 @@ end
function test_coordinates_no_plane()
local r = region.create(0, 0, "mountain")
- local f = faction.create("noplane@eressea.de", "human", "de")
+ local f = faction.create("human", "noplane@eressea.de", "de")
local u = unit.create(f, r, 1)
init_reports()
write_report(f)
@@ -56,7 +56,7 @@ end
function test_show_shadowmaster_attacks()
local r = region.create(0, 0, "plain")
- local f = faction.create("noreply@eressea.de", "human", "de")
+ local f = faction.create("human", "noreply@eressea.de", "de")
local u = unit.create(f, r, 1)
u.race = "shadowmaster"
u:clear_orders()
@@ -71,7 +71,7 @@ end
function test_coordinates_named_plane()
local p = plane.create(0, -3, -3, 7, 7, "Hell")
local r = region.create(0, 0, "mountain")
- local f = faction.create("noreply@eressea.de", "human", "de")
+ local f = faction.create("human", "noreply@eressea.de", "de")
local u = unit.create(f, r, 1)
init_reports()
write_report(f)
@@ -82,7 +82,7 @@ end
function test_coordinates_noname_plane()
local p = plane.create(0, -3, -3, 7, 7, "")
local r = region.create(0, 0, "mountain")
- local f = faction.create("noreply@eressea.de", "human", "de")
+ local f = faction.create("human", "noreply@eressea.de", "de")
local u = unit.create(f, r, 1)
init_reports()
write_report(f)
@@ -93,7 +93,7 @@ end
function test_lighthouse()
eressea.free_game()
local r = region.create(0, 0, "mountain")
- local f = faction.create("noreply@eressea.de", "human", "de")
+ local f = faction.create("human", "noreply@eressea.de", "de")
region.create(1, 0, "mountain")
region.create(2, 0, "ocean")
region.create(0, 1, "firewall")
diff --git a/scripts/tests/spells.lua b/scripts/tests/spells.lua
new file mode 100644
index 000000000..e3c0a3021
--- /dev/null
+++ b/scripts/tests/spells.lua
@@ -0,0 +1,83 @@
+require 'lunit'
+module("tests.spells", package.seeall, lunit.testcase)
+
+function setup()
+ eressea.free_game()
+ eressea.settings.set("nmr.removenewbie", "0")
+ eressea.settings.set("nmr.timeout", "0")
+ eressea.settings.set("NewbieImmunity", "0")
+ eressea.settings.set("rules.food.flags", "4")
+ eressea.settings.set("rules.encounters", "0")
+ eressea.settings.set("magic.regeneration.enable", "0")
+end
+
+function test_create_bogus()
+ local r = region.create(0, 0, "plain")
+ local f = faction.create("human")
+ local u = unit.create(f, r, 1)
+ u.race = "elf"
+ u:set_skill("magic", 10)
+ u.magic = 'gwyrrd'
+ u:clear_orders()
+ u:add_order("ZAUBERE 'Erschaffe Katastrophe'")
+ process_orders()
+ assert_equal(f.messages[3], 'error173') -- HACKity HACK
+end
+
+function test_create_roi()
+ local r = region.create(0, 0, "plain")
+ local f = faction.create("human")
+ local u = unit.create(f, r, 1)
+ u.race = "elf"
+ u:set_skill("magic", 10)
+ u.magic = 'gwyrrd'
+ u.aura = 100
+ u:add_item("money", 3000)
+ u:add_spell("create_roi")
+ u:clear_orders()
+ u:add_order("ZAUBERE 'Erschaffe einen Ring der Unsichtbarkeit'")
+ local amax = u.aura_max
+ process_orders()
+ assert_equal(1, u:get_item("roi"))
+ assert_equal(50, u.aura)
+ assert_equal(amax - 1, u.aura_max)
+end
+
+function test_create_aots()
+ local r = region.create(0, 0, "plain")
+ local f = faction.create("human")
+ local u = unit.create(f, r, 1)
+ u.race = "elf"
+ u:set_skill("magic", 10)
+ u.magic = 'gwyrrd'
+ u.aura = 100
+ u:add_item("money", 3000)
+ u:add_spell("create_aots")
+ u:clear_orders()
+ u:add_order("ZAUBERE 'Erschaffe ein Amulett des wahren Sehens'")
+ local amax = u.aura_max
+ process_orders()
+ assert_equal(1, u:get_item("aots"))
+ assert_equal(50, u.aura)
+ assert_equal(amax - 1, u.aura_max)
+end
+
+function test_create_dreameye()
+ local r = region.create(0, 0, "plain")
+ local f = faction.create("human")
+ local u = unit.create(f, r, 1)
+ u.race = "elf"
+ u:set_skill("magic", 10)
+ u.magic = 'gwyrrd'
+ u.aura = 100
+ u:add_item("dragonhead", 1)
+ u:add_spell("create_dreameye")
+ u:clear_orders()
+ u:add_order("ZAUBERE 'Erschaffe ein Traumauge'")
+ local amax = u.aura_max
+ process_orders()
+ assert_equal(1, u:get_item("dreameye"))
+ assert_equal(100, u.aura)
+ assert_equal(amax - 5, u.aura_max)
+end
+
diff --git a/scripts/tests/storage.lua b/scripts/tests/storage.lua
index c262652db..32fbe9ef3 100644
--- a/scripts/tests/storage.lua
+++ b/scripts/tests/storage.lua
@@ -8,7 +8,7 @@ end
function test_store_unit()
local r = region.create(0, 0, "plain")
- local f = faction.create("noreply15@eressea.de", "human", "de")
+ local f = faction.create("human", "noreply15@eressea.de", "de")
local u = unit.create(f, r, 1)
local fid = f.id
u:add_item("money", u.number * 100)
@@ -20,7 +20,7 @@ function test_store_unit()
eressea.free_game()
-- recreate world:
r = region.create(0, 0, "plain")
- f = faction.create("noreply16@eressea.de", "human", "de")
+ f = faction.create("human", "noreply16@eressea.de", "de")
f.id = fid
store = storage.create(filename, "rb")
assert_not_nil(store)
diff --git a/scripts/tests/study.lua b/scripts/tests/study.lua
index 9bb8cda5e..2a713dd43 100644
--- a/scripts/tests/study.lua
+++ b/scripts/tests/study.lua
@@ -24,7 +24,7 @@ end
function test_study()
local r = region.create(0, 0, "plain")
- local f = faction.create("test@example.com", "human", "de")
+ local f = faction.create("human", "test@example.com", "de")
local u = unit.create(f, r, 1)
u:add_order("LERNEN Armbrust")
process_orders()
@@ -33,7 +33,7 @@ end
function test_study_expensive()
local r = region.create(0, 0, "plain")
- local f = faction.create("test@example.com", "human", "de")
+ local f = faction.create("human", "test@example.com", "de")
local u = unit.create(f, r, 1)
eressea.settings.set("skills.cost.alchemy", "50")
eressea.settings.set("rules.encounters", "0")
@@ -46,7 +46,7 @@ end
function test_unit_spells()
local r = region.create(0, 0, "plain")
- local f = faction.create("test@example.com", "human", "de")
+ local f = faction.create("human", "test@example.com", "de")
local u = unit.create(f, r, 1)
u.magic = "gray"
u:set_skill("magic", 1)
@@ -76,7 +76,7 @@ end
function test_study_no_teacher()
local r = region.create(0, 0, "plain")
- local f = faction.create("test@example.com", "human", "de")
+ local f = faction.create("human", "test@example.com", "de")
local u1 = make_student(f, r, 1)
u1:set_skill("crossbow", 1)
process_orders()
@@ -85,7 +85,7 @@ end
function test_study_with_teacher()
local r = region.create(0, 0, "plain")
- local f = faction.create("test@example.com", "human", "de")
+ local f = faction.create("human", "test@example.com", "de")
local u1 = make_student(f, r, 1)
make_teacher(u1)
@@ -96,7 +96,7 @@ end
function test_study_too_many_students()
local r = region.create(0, 0, "plain")
- local f = faction.create("test@example.com", "human", "de")
+ local f = faction.create("human", "test@example.com", "de")
local u1 = make_student(f, r, 20, "Taktik")
u1.name = "Student"
u1:add_item("money", 201*u1.number)
@@ -107,7 +107,7 @@ end
function test_study_multiple_teachers()
local r = region.create(0, 0, "plain")
- local f = faction.create("test@example.com", "human", "de")
+ local f = faction.create("human", "test@example.com", "de")
local u1 = make_student(f, r, 20, "Taktik")
u1.name = "Student"
u1:add_item("money", 201*u1.number)
diff --git a/scripts/tests/xmas.lua b/scripts/tests/xmas.lua
index 459984901..304cc333a 100644
--- a/scripts/tests/xmas.lua
+++ b/scripts/tests/xmas.lua
@@ -15,7 +15,7 @@ end
function test_snowglobe_fail()
local r1 = region.create(0, 0, "glacier")
local r2 = region.create(1, 0, "ocean")
- local f = faction.create("snowglobe1@eressea.de", "human", "de")
+ local f = faction.create("human", "snowglobe1@eressea.de", "de")
local u = unit.create(f, r1, 1)
u:add_item("snowglobe", 1)
u:clear_orders()
@@ -30,7 +30,7 @@ end
function test_snowglobe_missing_direction()
local r1 = region.create(0, 0, "glacier")
local r2 = region.create(1, 0, "ocean")
- local f = faction.create("snowglobe1@eressea.de", "human", "de")
+ local f = faction.create("human", "snowglobe1@eressea.de", "de")
local u = unit.create(f, r1, 1)
u:add_item("snowglobe", 1)
u:clear_orders()
@@ -44,7 +44,7 @@ end
function test_snowglobe()
local r1 = region.create(0, 0, "glacier")
local r2 = region.create(1, 0, "ocean")
- local f = faction.create("snowglobe2@eressea.de", "human", "de")
+ local f = faction.create("human", "snowglobe2@eressea.de", "de")
local u = unit.create(f, r1, 1)
local fail = 0
u:add_item("snowglobe", have)
@@ -62,7 +62,7 @@ end
local function use_tree(terrain)
local r = region.create(0, 0, terrain)
- local f = faction.create("noreply@eressea.de", "human", "de")
+ local f = faction.create("human", "noreply@eressea.de", "de")
local u1 = unit.create(f, r, 5)
r:set_resource("tree", 0)
u1:add_item("xmastree", 1)
@@ -86,7 +86,7 @@ function test_stardust()
eressea.settings.set("rules.economy.repopulate_maximum", 0)
local r = region.create(0, 0, "plain")
r:set_resource("peasant", 10)
- local f = faction.create("noreply@eressea.de", "human", "de")
+ local f = faction.create("human", "noreply@eressea.de", "de")
local u = unit.create(f, r, 5)
u:add_item("stardust", 1)
u:clear_orders()
diff --git a/share/debian-7_8.supp b/share/debian-7_8.supp
index 99eefafa4..f6fabe6e7 100644
--- a/share/debian-7_8.supp
+++ b/share/debian-7_8.supp
@@ -50,11 +50,4 @@
obj:/usr/lib/x86_64-linux-gnu/liblua5.2.so.0.0.0
obj:/usr/lib/x86_64-linux-gnu/liblua5.2.so.0.0.0
fun:lua_isnumber
- fun:class_index_event
- obj:/usr/lib/x86_64-linux-gnu/liblua5.2.so.0.0.0
- obj:/usr/lib/x86_64-linux-gnu/liblua5.2.so.0.0.0
- obj:/usr/lib/x86_64-linux-gnu/liblua5.2.so.0.0.0
- obj:/usr/lib/x86_64-linux-gnu/liblua5.2.so.0.0.0
- obj:/usr/lib/x86_64-linux-gnu/liblua5.2.so.0.0.0
- obj:/usr/lib/x86_64-linux-gnu/liblua5.2.so.0.0.0
}
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index f9c92ff2c..c4c306118 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -187,43 +187,52 @@ target_link_libraries(eressea
${INIPARSER_LIBRARIES}
)
+add_executable(convert convert.c)
+target_link_libraries(convert
+ game
+ ${LUA_MATH_LIBRARY}
+ ${STORAGE_LIBRARIES}
+ ${CLIBS_LIBRARIES}
+ ${INIPARSER_LIBRARIES}
+)
+
set(TESTS_SRC
- monsters.test.c
- names.test.c
- donations.test.c
- wormhole.test.c
- alchemy.test.c
- guard.test.c
test_eressea.c
tests.c
+ alchemy.test.c
battle.test.c
- vortex.test.c
- tests.test.c
- volcano.test.c
- reports.test.c
+ calendar.test.c
creport.test.c
- report.test.c
- summary.test.c
- travelthru.test.c
direction.test.c
+ donations.test.c
economy.test.c
+ give.test.c
+ guard.test.c
json.test.c
keyword.test.c
- give.test.c
laws.test.c
lighthouse.test.c
magic.test.c
market.test.c
monsters.test.c
move.test.c
+ names.test.c
piracy.test.c
prefix.test.c
renumber.test.c
+ reports.test.c
+ report.test.c
+ summary.test.c
skill.test.c
spells.test.c
spy.test.c
study.test.c
+ tests.test.c
+ travelthru.test.c
upkeep.test.c
+ volcano.test.c
+ vortex.test.c
+ wormhole.test.c
spells/flyingship.test.c
spells/magicresistance.test.c
triggers/shock.test.c
@@ -268,6 +277,7 @@ endif(CURSES_FOUND)
if (LIBXML2_FOUND)
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/attributes/CMakeLists.txt b/src/attributes/CMakeLists.txt
index d0aa252ee..8be9dc7ff 100644
--- a/src/attributes/CMakeLists.txt
+++ b/src/attributes/CMakeLists.txt
@@ -12,7 +12,6 @@ follow.c
hate.c
iceberg.c
key.c
-matmod.c
moved.c
movement.c
dict.c
diff --git a/src/attributes/attributes.c b/src/attributes/attributes.c
index 42f5247fe..f699fdb57 100644
--- a/src/attributes/attributes.c
+++ b/src/attributes/attributes.c
@@ -25,6 +25,7 @@ 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"
@@ -58,6 +59,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include
+
attrib_type at_unitdissolve = {
"unitdissolve", NULL, NULL, NULL, a_writechars, a_readchars
};
@@ -100,7 +102,6 @@ void register_attributes(void)
at_register(&at_group);
at_register(&at_building_generic_type);
- at_register(&at_maxmagicians);
at_register(&at_npcfaction);
/* connection-typen */
@@ -112,6 +113,8 @@ void register_attributes(void)
at_register(&at_germs);
+ at_deprecate("maxmagicians", a_readint); /* factions with differnt magician limits, probably unused */
+ at_deprecate("hurting", a_readint); /* an old arena attribute */
at_deprecate("xontormiaexpress", a_readint); /* required for old datafiles */
at_deprecate("orcification", a_readint); /* required for old datafiles */
at_deprecate("lua", read_ext); /* required for old datafiles */
diff --git a/src/attributes/fleechance.c b/src/attributes/fleechance.c
index afba2d301..b8012fba5 100644
--- a/src/attributes/fleechance.c
+++ b/src/attributes/fleechance.c
@@ -38,8 +38,3 @@ attrib *make_fleechance(float fleechance)
a->data.flt = fleechance;
return a;
}
-
-void init_fleechance(void)
-{
- at_register(&at_fleechance);
-}
diff --git a/src/attributes/fleechance.h b/src/attributes/fleechance.h
index b2f75671c..d5817b8b7 100644
--- a/src/attributes/fleechance.h
+++ b/src/attributes/fleechance.h
@@ -25,7 +25,6 @@ extern "C" {
extern struct attrib_type at_fleechance;
struct attrib *make_fleechance(float fleechance);
- void init_fleechance(void);
#ifdef __cplusplus
}
diff --git a/src/attributes/matmod.c b/src/attributes/matmod.c
deleted file mode 100644
index 0cf1955d8..000000000
--- a/src/attributes/matmod.c
+++ /dev/null
@@ -1,41 +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 "matmod.h"
-
-#include
-#include
-
-attrib_type at_matmod = {
- "matmod",
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- ATF_PRESERVE
-};
-
-attrib *make_matmod(mm_fun function)
-{
- attrib *a = a_new(&at_matmod);
- a->data.f = (void(*)(void))function;
- return a;
-}
diff --git a/src/battle.c b/src/battle.c
index 018133516..19f30e59c 100644
--- a/src/battle.c
+++ b/src/battle.c
@@ -576,10 +576,7 @@ static weapon *select_weapon(const troop t, bool attacking,
static bool i_canuse(const unit * u, const item_type * itype)
{
- if (itype->canuse) {
- return itype->canuse(u, itype);
- }
- return true;
+ return rc_can_use(u_race(u), itype);
}
static int
@@ -1208,11 +1205,12 @@ terminate(troop dt, troop at, int type, const char *damage, bool missile)
if (type != AT_COMBATSPELL && type != AT_SPELL) {
if (rule_damage & DAMAGE_CRITICAL) {
double kritchance = (sk * 3 - sd) / 200.0;
+ int maxk = 4;
kritchance = MAX(kritchance, 0.005);
kritchance = MIN(0.9, kritchance);
- while (chance(kritchance)) {
+ while (maxk-- && chance(kritchance)) {
da += dice_rand(damage);
}
}
@@ -1752,15 +1750,9 @@ void do_combatmagic(battle * b, combatmagic_t was)
fighter *fig = co->magician.fig;
const spell *sp = co->sp;
- level = co->level;
- if (!sp->cast) {
- log_error("spell '%s' has no function.\n", sp->sname);
- }
- else {
- level = sp->cast(co);
- if (level > 0) {
- pay_spell(fig->unit, sp, level, 1);
- }
+ level = cast_spell(co);
+ if (level > 0) {
+ pay_spell(fig->unit, sp, level, 1);
}
}
}
@@ -1774,7 +1766,7 @@ static int cast_combatspell(troop at, const spell * sp, int level, double force)
castorder co;
create_castorder_combat(&co, at.fighter, sp, level, force);
- level = sp->cast(&co);
+ level = cast_spell(&co);
free_castorder(&co);
if (level > 0) {
pay_spell(at.fighter->unit, sp, level, 1);
@@ -1843,12 +1835,7 @@ static void do_combatspell(troop at)
return;
}
- if (!sp->cast) {
- log_error("spell '%s' has no function.\n", sp->sname);
- }
- else {
- level = cast_combatspell(at, sp, level, power);
- }
+ level = cast_combatspell(at, sp, level, power);
}
/* Sonderattacken: Monster patzern nicht und zahlen auch keine
@@ -1863,9 +1850,6 @@ static void do_extra_spell(troop at, const att * a)
if (!sp) {
log_error("no such spell: '%s'", a->data.sp->name);
}
- else if (sp->cast == NULL) {
- log_error("spell '%s' has no function.", sp->sname);
- }
else {
assert(a->level > 0);
cast_combatspell(at, sp, a->level, a->level);
diff --git a/src/battle.h b/src/battle.h
index 85e65cf66..4e20d00d8 100644
--- a/src/battle.h
+++ b/src/battle.h
@@ -123,13 +123,8 @@ extern "C" {
typedef struct weapon {
int count, used;
const struct weapon_type *type;
-# ifdef LOMEM
- int attackskill : 8;
- int defenseskill : 8;
-# else
int attackskill;
int defenseskill;
-# endif
} weapon;
/*** fighter::person::flags ***/
diff --git a/src/bind_faction.c b/src/bind_faction.c
index 518ccccac..f9321f6b5 100644
--- a/src/bind_faction.c
+++ b/src/bind_faction.c
@@ -268,6 +268,23 @@ static int tolua_faction_setkey(lua_State * L)
return 0;
}
+static int tolua_faction_get_messages(lua_State * L)
+{
+ faction *self = (faction *)tolua_tousertype(L, 1, 0);
+ int i = 1;
+ mlist *ml;
+ if (!self->msgs) {
+ return 0;
+ }
+ lua_newtable(L);
+ for (ml = self->msgs->begin; ml; ml = ml->next, ++i) {
+ lua_pushnumber(L, i);
+ lua_pushstring(L, ml->msg->type->name);
+ lua_rawset(L, -3);
+ }
+ return 1;
+}
+
static int tolua_faction_count_msg_type(lua_State *L) {
faction *self = (faction *)tolua_tousertype(L, 1, 0);
const char *str = tolua_tostring(L, 2, 0);
@@ -401,8 +418,8 @@ static int tolua_faction_get(lua_State * L)
static int tolua_faction_create(lua_State * L)
{
- const char *email = tolua_tostring(L, 1, 0);
- const char *racename = tolua_tostring(L, 2, 0);
+ const char *racename = tolua_tostring(L, 1, 0);
+ const char *email = tolua_tostring(L, 2, 0);
const char *lang = tolua_tostring(L, 3, 0);
struct locale *loc = lang ? get_locale(lang) : default_locale;
faction *f = NULL;
@@ -637,6 +654,7 @@ void tolua_faction_open(lua_State * L)
/* tech debt hack, siehe https://paper.dropbox.com/doc/Weihnachten-2015-5tOx5r1xsgGDBpb0gILrv#:h=Probleme-mit-Tests-(Nachtrag-0 */
tolua_function(L, TOLUA_CAST "count_msg_type", tolua_faction_count_msg_type);
+ tolua_variable(L, TOLUA_CAST "messages", tolua_faction_get_messages, NULL);
tolua_function(L, TOLUA_CAST "get_key", tolua_faction_getkey);
tolua_function(L, TOLUA_CAST "set_key", tolua_faction_setkey);
diff --git a/src/bind_region.c b/src/bind_region.c
index f0c2ba87b..2f9309549 100644
--- a/src/bind_region.c
+++ b/src/bind_region.c
@@ -19,6 +19,7 @@ without prior permission by the authors of Eressea.
#include "chaos.h"
#include
+#include
#include
#include
#include
@@ -29,6 +30,7 @@ without prior permission by the authors of Eressea.
#include
#include
#include
+#include
#include
#include
#include
@@ -46,6 +48,23 @@ without prior permission by the authors of Eressea.
#include
#include
+static int tolua_region_count_msg_type(lua_State *L) {
+ region *self = (region *)tolua_tousertype(L, 1, 0);
+ const char *str = tolua_tostring(L, 2, 0);
+ int n = 0;
+ if (self->msgs) {
+ mlist * ml = self->msgs->begin;
+ while (ml) {
+ if (strcmp(str, ml->msg->type->name) == 0) {
+ ++n;
+ }
+ ml = ml->next;
+ }
+ }
+ lua_pushinteger(L, n);
+ return 1;
+}
+
int tolua_regionlist_next(lua_State * L)
{
region **region_ptr = (region **)lua_touserdata(L, lua_upvalueindex(1));
@@ -341,20 +360,16 @@ static int tolua_region_get_resourcelevel(lua_State * L)
#define LUA_ASSERT(c, s) if (!(c)) { log_error("%s(%d): %s\n", __FILE__, __LINE__, (s)); return 0; }
-static critbit_tree * special_resources(void)
-{
- static critbit_tree cb = CRITBIT_TREE();
- if (!cb.root) {
- const char * special[] = { "seed", "sapling", "tree", "grave", "chaos", 0 };
- char buffer[32];
- int i;
- for (i = 0; special[i]; ++i) {
- size_t len = strlen(special[i]);
- len = cb_new_kv(special[i], len, &i, sizeof(int), buffer);
- cb_insert(&cb, buffer, len);
+static int special_resource(const char *type) {
+ const char * special[] = { "seed", "sapling", "tree", "grave", "chaos", 0 };
+ int i;
+
+ for (i = 0; special[i]; ++i) {
+ if (strcmp(type, special[i]) == 0) {
+ return i;
}
}
- return &cb;
+ return -1;
}
static int tolua_region_get_resource(lua_State * L)
@@ -362,32 +377,27 @@ static int tolua_region_get_resource(lua_State * L)
region *r;
const char *type;
const resource_type *rtype;
- int result = 0;
- void * match;
- critbit_tree * cb = special_resources();
+ int result;
r = (region *)tolua_tousertype(L, 1, 0);
LUA_ASSERT(r != NULL, "invalid parameter");
type = tolua_tostring(L, 2, 0);
LUA_ASSERT(type != NULL, "invalid parameter");
-
- if (cb_find_prefix(cb, type, strlen(type) + 1, &match, 1, 0)) {
- cb_get_kv(match, &result, sizeof(result));
- switch (result) {
- case 0:
- case 1:
- case 2:
- result = rtrees(r, result);
- break;
- case 3:
- result = deathcount(r);
- break;
- case 4:
- result = get_chaoscount(r);
- break;
- }
- }
- else {
+
+ result = special_resource(type);
+ switch (result) {
+ case 0:
+ case 1:
+ case 2:
+ result = rtrees(r, result);
+ break;
+ case 3:
+ result = deathcount(r);
+ break;
+ case 4:
+ result = get_chaoscount(r);
+ break;
+ default:
rtype = rt_find(type);
if (rtype) {
result = region_getresource(r, rtype);
@@ -406,27 +416,23 @@ static int tolua_region_set_resource(lua_State * L)
region *r = (region *)tolua_tousertype(L, 1, 0);
const char *type = tolua_tostring(L, 2, 0);
int result, value = (int)tolua_tonumber(L, 3, 0);
- critbit_tree * cb = special_resources();
- void * match;
+ const resource_type *rtype;
- if (cb_find_prefix(cb, type, strlen(type) + 1, &match, 1, 0)) {
- cb_get_kv(match, &result, sizeof(result));
- switch (result) {
- case 0:
- case 1:
- case 2:
- rsettrees(r, result, value);
- break;
- case 3:
- deathcounts(r, value - deathcount(r));
- break;
- case 4:
- add_chaoscount(r, value - get_chaoscount(r));
- break;
- }
- }
- else {
- const resource_type *rtype = rt_find(type);
+ result = special_resource(type);
+ switch (result) {
+ case 0:
+ case 1:
+ case 2:
+ rsettrees(r, result, value);
+ break;
+ case 3:
+ deathcounts(r, value - deathcount(r));
+ break;
+ case 4:
+ add_chaoscount(r, value - get_chaoscount(r));
+ break;
+ default:
+ rtype = rt_find(type);
if (rtype != NULL) {
region_setresource(r, rtype, value);
}
@@ -665,6 +671,27 @@ static int tolua_distance(lua_State * L)
return 1;
}
+static int tolua_region_get_curse(lua_State *L) {
+ region *self = (region *)tolua_tousertype(L, 1, 0);
+ const char *name = tolua_tostring(L, 2, 0);
+ if (self->attribs) {
+ curse * c = get_curse(self->attribs, ct_find(name));
+ if (c) {
+ lua_pushnumber(L, curse_geteffect(c));
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int tolua_region_has_attrib(lua_State *L) {
+ region *self = (region *)tolua_tousertype(L, 1, 0);
+ const char *name = tolua_tostring(L, 2, 0);
+ attrib * a = a_find(self->attribs, at_find(name));
+ lua_pushboolean(L, a != NULL);
+ return 1;
+}
+
void tolua_region_open(lua_State * L)
{
/* register user types */
@@ -684,6 +711,10 @@ void tolua_region_open(lua_State * L)
tolua_function(L, TOLUA_CAST "destroy", tolua_region_destroy);
tolua_function(L, TOLUA_CAST "__tostring", tolua_region_tostring);
+ tolua_function(L, TOLUA_CAST "count_msg_type", tolua_region_count_msg_type);
+
+ tolua_function(L, TOLUA_CAST "get_curse", &tolua_region_get_curse);
+ tolua_function(L, TOLUA_CAST "has_attrib", &tolua_region_has_attrib);
/* flags */
tolua_variable(L, TOLUA_CAST "blocked", tolua_region_get_blocked, tolua_region_set_blocked);
diff --git a/src/bind_ship.c b/src/bind_ship.c
index 515fa8de3..c5e0735ed 100644
--- a/src/bind_ship.c
+++ b/src/bind_ship.c
@@ -16,11 +16,13 @@ without prior permission by the authors of Eressea.
#include "move.h"
+#include
#include
#include
#include
#include
+#include
#include
#include
@@ -198,6 +200,27 @@ static int tolua_ship_set_damage(lua_State * L)
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);
+ if (self->attribs) {
+ curse * c = get_curse(self->attribs, ct_find(name));
+ if (c) {
+ lua_pushnumber(L, curse_geteffect(c));
+ return 1;
+ }
+ }
+ return 0;
+}
+
+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);
+ attrib * a = a_find(self->attribs, at_find(name));
+ lua_pushboolean(L, a != NULL);
+ return 1;
+}
+
void tolua_ship_open(lua_State * L)
{
/* register user types */
@@ -225,6 +248,10 @@ void tolua_ship_open(lua_State * L)
tolua_variable(L, TOLUA_CAST "type", tolua_ship_get_type, 0);
tolua_variable(L, TOLUA_CAST "damage", tolua_ship_get_damage,
tolua_ship_set_damage);
+
+ tolua_function(L, TOLUA_CAST "get_curse", &tolua_ship_get_curse);
+ tolua_function(L, TOLUA_CAST "has_attrib", &tolua_ship_has_attrib);
+
tolua_function(L, TOLUA_CAST "create", tolua_ship_create);
}
tolua_endmodule(L);
diff --git a/src/bind_unit.c b/src/bind_unit.c
old mode 100755
new mode 100644
index 0358e1938..1d6579b0e
--- a/src/bind_unit.c
+++ b/src/bind_unit.c
@@ -193,6 +193,13 @@ static int tolua_unit_set_id(lua_State * L)
return 0;
}
+static int tolua_unit_get_auramax(lua_State * L)
+{
+ unit *self = (unit *)tolua_tousertype(L, 1, 0);
+ lua_pushinteger(L, max_spellpoints(self->region, self));
+ return 1;
+}
+
static int tolua_unit_get_hpmax(lua_State * L)
{
unit *self = (unit *)tolua_tousertype(L, 1, 0);
@@ -512,15 +519,10 @@ static void unit_castspell(unit * u, const char *name, int level)
if (sp) {
spellbook *book = unit_get_spellbook(u);
if (spellbook_get(book, sp)) {
- if (!sp->cast) {
- log_error("spell '%s' has no function.\n", sp->sname);
- }
- else {
- castorder co;
- create_castorder(&co, u, 0, sp, u->region, level, (double)level, 0, 0, 0);
- sp->cast(&co);
- free_castorder(&co);
- }
+ castorder co;
+ create_castorder(&co, u, 0, sp, u->region, level, (double)level, 0, 0, 0);
+ cast_spell(&co);
+ free_castorder(&co);
}
}
}
@@ -771,17 +773,29 @@ static int tolua_unit_get_orders(lua_State * L)
return 1;
}
-static int tolua_unit_is_cursed(lua_State *L) {
+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);
- lua_pushboolean(L, self->attribs && curse_active(get_curse(self->attribs, ct_find(name))));
- return 1;
+ if (self->attribs) {
+ curse * c = get_curse(self->attribs, ct_find(name));
+ if (c) {
+ lua_pushnumber(L, curse_geteffect(c));
+ return 1;
+ }
+ }
+ return 0;
}
static int tolua_unit_has_attrib(lua_State *L) {
unit *self = (unit *)tolua_tousertype(L, 1, 0);
const char *name = tolua_tostring(L, 2, 0);
- attrib * a = a_find(self->attribs, at_find(name));
+ attrib * a = self->attribs;
+ while (a) {
+ if (strcmp(a->type->name, name) == 0) {
+ break;
+ }
+ a = a->nexttype;
+ }
lua_pushboolean(L, a != NULL);
return 1;
}
@@ -972,7 +986,7 @@ void tolua_unit_open(lua_State * L)
tolua_function(L, TOLUA_CAST "clear_orders", &tolua_unit_clear_orders);
tolua_variable(L, TOLUA_CAST "orders", &tolua_unit_get_orders, 0);
- tolua_function(L, TOLUA_CAST "is_cursed", &tolua_unit_is_cursed);
+ 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: */
@@ -1026,6 +1040,7 @@ void tolua_unit_open(lua_State * L)
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_function(L, TOLUA_CAST "show", &tolua_bufunit);
}
diff --git a/src/bindings.c b/src/bindings.c
index 1d6270b35..33d609ee0 100755
--- a/src/bindings.c
+++ b/src/bindings.c
@@ -92,6 +92,20 @@ TOLUA_PKG(locale);
TOLUA_PKG(log);
TOLUA_PKG(game);
+int tolua_toid(lua_State * L, int idx, int def)
+{
+ int no = 0;
+ int type = lua_type(L, idx);
+ if (type == LUA_TNUMBER) {
+ no = (int)tolua_tonumber(L, idx, def);
+ }
+ else {
+ const char *str = tolua_tostring(L, idx, NULL);
+ no = str ? atoi36(str) : def;
+ }
+ return no;
+}
+
int log_lua_error(lua_State * L)
{
const char *error = lua_tostring(L, -1);
@@ -217,7 +231,7 @@ static int tolua_setkey(lua_State * L)
return 0;
}
-static int tolua_rng_int(lua_State * L)
+static int tolua_random(lua_State * L)
{
lua_pushinteger(L, rng_int());
return 1;
@@ -907,7 +921,7 @@ static int init_data(const char *filename, const char *catalog)
if (l) {
return l;
}
- if (turn < 0) {
+ if (turn <= 0) {
turn = first_turn();
}
return 0;
@@ -976,6 +990,12 @@ static void parse_inifile(lua_State * L, const dictionary * d, const char *secti
}
}
+static int lua_rng_default(lua_State *L) {
+ UNUSED_ARG(L);
+ random_source_inject_constant(0);
+ return 0;
+}
+
void tolua_bind_open(lua_State * L);
int tolua_bindings_open(lua_State * L, const dictionary *inifile)
@@ -997,6 +1017,14 @@ int tolua_bindings_open(lua_State * L, const dictionary *inifile)
tolua_module(L, NULL, 0);
tolua_beginmodule(L, NULL);
{
+ tolua_module(L, TOLUA_CAST "rng", 1);
+ tolua_beginmodule(L, TOLUA_CAST "rng");
+ {
+ tolua_function(L, TOLUA_CAST "inject", lua_rng_default);
+ tolua_function(L, TOLUA_CAST "random", tolua_random);
+ }
+ tolua_endmodule(L);
+ tolua_function(L, TOLUA_CAST "rng_int", tolua_random);
tolua_cclass(L, TOLUA_CAST "alliance", TOLUA_CAST "alliance",
TOLUA_CAST "", NULL);
tolua_beginmodule(L, TOLUA_CAST "alliance");
@@ -1086,7 +1114,6 @@ int tolua_bindings_open(lua_State * L, const dictionary *inifile)
tolua_function(L, TOLUA_CAST "get_key", tolua_getkey);
tolua_function(L, TOLUA_CAST "set_key", tolua_setkey);
tolua_function(L, TOLUA_CAST "translate", &tolua_translate);
- tolua_function(L, TOLUA_CAST "rng_int", tolua_rng_int);
tolua_function(L, TOLUA_CAST "spells", tolua_get_spells);
tolua_function(L, TOLUA_CAST "read_xml", tolua_read_xml);
} tolua_endmodule(L);
diff --git a/src/bindings.h b/src/bindings.h
index 354bb199a..5cb64a038 100755
--- a/src/bindings.h
+++ b/src/bindings.h
@@ -18,6 +18,7 @@ extern "C" {
struct _dictionary_;
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);
diff --git a/src/calendar.c b/src/calendar.c
index d2a70c974..6fd717429 100644
--- a/src/calendar.c
+++ b/src/calendar.c
@@ -1,20 +1,35 @@
#include
#include "calendar.h"
+#include "move.h" /* storms */
+
#include
#include
#include
+#include
int first_month = 0;
-int weeks_per_month = 4;
+int weeks_per_month = 3;
int months_per_year = 12;
-char **seasonnames = NULL;
+const char *seasonnames[CALENDAR_SEASONS] = { "winter", "spring", "summer", "fall" };
char **weeknames = NULL;
char **weeknames2 = NULL;
-char **monthnames = NULL;
int *month_season = NULL;
-char *agename = NULL;
-int seasons = 0;
+
+const char *calendar_month(int index)
+{
+ static char result[20];
+ snprintf(result, sizeof(result), "month_%d", index + 1);
+ return result;
+}
+
+const char *calendar_era(void)
+{
+ static char result[20];
+ int era = config_get_int("game.era", 1);
+ snprintf(result, sizeof(result), "age_%d", era);
+ return result;
+}
int first_turn(void)
{
@@ -27,8 +42,7 @@ const gamedate *get_gamedate(int turn, gamedate * gd)
int t = turn - first_turn();
assert(gd);
- if (t < 0)
- t = turn;
+ assert(t>=0);
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 */
@@ -41,36 +55,23 @@ void calendar_cleanup(void)
{
int i;
- free(agename);
-
- if (seasonnames) {
- for (i = 0; i != seasons; ++i) {
- free(seasonnames[i]);
- }
- free(seasonnames);
- seasonnames = 0;
- }
-
- if (monthnames) {
- for (i = 0; i != months_per_year; ++i) {
- free(monthnames[i]);
- }
- free(storms);
- storms = 0;
- free(month_season);
- month_season = 0;
- free(monthnames);
- monthnames = 0;
- }
-
for (i = 0; i != weeks_per_month; ++i) {
if (weeknames)
free(weeknames[i]);
if (weeknames2)
free(weeknames2[i]);
}
+
+ free(storms);
+ storms = 0;
+ free(month_season);
+ month_season = 0;
free(weeknames);
weeknames = 0;
free(weeknames2);
weeknames2 = 0;
+
+ first_month = 0;
+ weeks_per_month = 3;
+ months_per_year = 12;
}
diff --git a/src/calendar.h b/src/calendar.h
index d398cd77c..f8efa392c 100644
--- a/src/calendar.h
+++ b/src/calendar.h
@@ -11,17 +11,12 @@ extern "C" {
SEASON_SUMMER,
SEASON_AUTUMN
};
-
- extern char *agename;
- extern int first_month;
-
- extern int seasons;
- extern char **seasonnames;
+#define CALENDAR_SEASONS 4
+ extern const char *seasonnames[CALENDAR_SEASONS];
extern int months_per_year;
- extern char **monthnames;
extern int *month_season;
- extern int *storms; /* in movement.c */
+ extern int first_month;
extern char **weeknames;
extern char **weeknames2;
@@ -36,6 +31,8 @@ extern "C" {
const gamedate *get_gamedate(int turn, gamedate * gd);
void calendar_cleanup(void);
+const char *calendar_month(int index);
+const char *calendar_era(void);
int first_turn(void);
#ifdef __cplusplus
diff --git a/src/calendar.test.c b/src/calendar.test.c
new file mode 100644
index 000000000..e858747ec
--- /dev/null
+++ b/src/calendar.test.c
@@ -0,0 +1,98 @@
+#include
+
+#include "calendar.h"
+
+#include
+
+#include
+#include "tests.h"
+
+static void test_calendar_config(CuTest * tc)
+{
+ gamedate gd;
+
+ test_setup();
+ get_gamedate(0, &gd);
+ CuAssertIntEquals(tc, 0, first_turn());
+ config_set_int("game.start", 42);
+ CuAssertIntEquals(tc, 42, first_turn());
+ test_cleanup();
+}
+
+static void test_calendar(CuTest * tc)
+{
+ gamedate gd;
+
+ test_setup();
+ get_gamedate(0, &gd);
+ CuAssertIntEquals(tc, 1, gd.year);
+ CuAssertIntEquals(tc, 0, gd.season);
+ CuAssertIntEquals(tc, 0, gd.month);
+ CuAssertIntEquals(tc, 0, gd.week);
+
+ get_gamedate(1, &gd);
+ CuAssertIntEquals(tc, 1, gd.year);
+ CuAssertIntEquals(tc, 0, gd.season);
+ CuAssertIntEquals(tc, 0, gd.month);
+ CuAssertIntEquals(tc, 1, gd.week);
+
+ get_gamedate(weeks_per_month, &gd);
+ CuAssertIntEquals(tc, 1, gd.year);
+ CuAssertIntEquals(tc, 0, gd.season);
+ CuAssertIntEquals(tc, 1, gd.month);
+ CuAssertIntEquals(tc, 0, gd.week);
+
+ get_gamedate(weeks_per_month*months_per_year, &gd);
+ CuAssertIntEquals(tc, 2, gd.year);
+ CuAssertIntEquals(tc, 0, gd.season);
+ CuAssertIntEquals(tc, 0, gd.month);
+ CuAssertIntEquals(tc, 0, gd.week);
+
+ config_set_int("game.start", 42);
+ get_gamedate(42, &gd);
+ CuAssertIntEquals(tc, 1, gd.year);
+ CuAssertIntEquals(tc, 0, gd.season);
+ CuAssertIntEquals(tc, 0, gd.month);
+ CuAssertIntEquals(tc, 0, gd.week);
+
+ first_month = 2;
+ get_gamedate(42, &gd);
+ CuAssertIntEquals(tc, 1, gd.year);
+ CuAssertIntEquals(tc, 0, gd.season);
+ CuAssertIntEquals(tc, 2, gd.month);
+ CuAssertIntEquals(tc, 0, gd.week);
+
+ test_cleanup();
+}
+
+static void test_calendar_season(CuTest * tc)
+{
+ gamedate gd;
+
+ test_setup();
+ month_season = calloc(months_per_year, sizeof(int));
+
+ get_gamedate(0, &gd);
+ CuAssertIntEquals(tc, 1, gd.year);
+ CuAssertIntEquals(tc, 0, gd.season);
+ CuAssertIntEquals(tc, 0, gd.month);
+ CuAssertIntEquals(tc, 0, gd.week);
+
+ month_season[1] = 1;
+ get_gamedate(weeks_per_month + 1, &gd);
+ CuAssertIntEquals(tc, 1, gd.year);
+ CuAssertIntEquals(tc, 1, gd.season);
+ CuAssertIntEquals(tc, 1, gd.month);
+ CuAssertIntEquals(tc, 1, gd.week);
+
+ test_cleanup();
+}
+
+CuSuite *get_calendar_suite(void)
+{
+ CuSuite *suite = CuSuiteNew();
+ SUITE_ADD_TEST(suite, test_calendar_config);
+ SUITE_ADD_TEST(suite, test_calendar);
+ SUITE_ADD_TEST(suite, test_calendar_season);
+ return suite;
+}
diff --git a/src/convert.c b/src/convert.c
new file mode 100644
index 000000000..a67c5a287
--- /dev/null
+++ b/src/convert.c
@@ -0,0 +1,44 @@
+#include
+
+
+#ifdef USE_LIBXML2
+#include
+#include
+#endif
+#include
+#include
+#include
+
+#include
+
+#include
+
+static int usage(void) {
+ return -1;
+}
+
+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();
+ xmlfile = argv[2];
+ catalog = argv[3];
+ read_xml(xmlfile, catalog);
+ write_rules("rules.dat");
+ return 0;
+ }
+#endif
+ if (strcmp(mode, "po")==0) {
+ return 0;
+ }
+ return usage();
+}
diff --git a/src/creport.c b/src/creport.c
index dc897e055..10dc4c323 100644
--- a/src/creport.c
+++ b/src/creport.c
@@ -87,19 +87,23 @@ bool opt_cr_absolute_coords = false;
/* globals */
#define C_REPORT_VERSION 66
-#define TAG_LOCALE "de"
-#ifdef TAG_LOCALE
+struct locale *crtag_locale(void) {
+ static struct locale * lang;
+ static int config;
+ if (config_changed(&config)) {
+ const char *lname = config_get("creport.tags");
+ lang = get_locale(lname ? lname : "de");
+ }
+ return lang;
+}
+
static const char *crtag(const char *key)
{
/* TODO: those locale lookups are shit, but static kills testing */
const char *result;
- const struct locale *lang = get_locale(TAG_LOCALE);
- result = LOC(lang, key);
+ result = LOC(crtag_locale(), key);
return result;
}
-#else
-#define crtag(x) (x)
-#endif
/*
* translation table
*/
@@ -134,7 +138,7 @@ static const char *translate(const char *key, const char *value)
return crtag(key);
}
-static void write_translations(FILE * F)
+static void report_translations(FILE * F)
{
int i;
fputs("TRANSLATION\n", F);
@@ -276,7 +280,7 @@ cr_output_curses(struct stream *out, const faction * viewer, const void *obj, ob
stream_printf(out, "EFFECTS\n");
}
stream_printf(out, "\"%d %s\"\n", data->value, translate(key,
- LOC(default_locale, key)));
+ LOC(viewer->locale, key)));
}
a = a->next;
}
@@ -1148,7 +1152,7 @@ cr_borders(const region * r, const faction * f, seen_mode mode, FILE * F)
const char *bname = border_name(b, r, f, GF_PURE);
bname = mkname("border", bname);
fprintf(F, "GRENZE %d\n", ++g);
- fprintf(F, "\"%s\";typ\n", LOC(default_locale, bname));
+ fprintf(F, "\"%s\";typ\n", LOC(f->locale, bname));
fprintf(F, "%d;richtung\n", d);
if (!b->type->transparent(b, f))
fputs("1;opaque\n", F);
@@ -1412,9 +1416,6 @@ static void cr_output_region(FILE * F, report_context * ctx, region * r)
}
}
}
- if (r->land) {
- print_items(F, r->land->items, f->locale);
- }
cr_output_curses_compat(F, f, r, TYP_REGION);
cr_borders(r, f, r->seen.mode, F);
if (r->seen.mode == seen_unit && is_astral(r)
@@ -1497,7 +1498,7 @@ report_computer(const char *filename, report_context * ctx, const char *bom)
static int rc_cache;
if (era < 0) {
- era = config_get_int("world.era", 1);
+ era = config_get_int("game.era", 1);
}
if (F == NULL) {
perror(filename);
@@ -1558,7 +1559,7 @@ report_computer(const char *filename, report_context * ctx, const char *bom)
translate(prefix, LOC(f->locale, prefix)));
}
fprintf(F, "%d;Rekrutierungskosten\n", f->race->recruitcost);
- fprintf(F, "%d;Anzahl Personen\n", count_all(f));
+ fprintf(F, "%d;Anzahl Personen\n", f->num_people);
fprintf(F, "\"%s\";Magiegebiet\n", magic_school[f->magiegebiet]);
if (rc_changed(&rc_cache)) {
@@ -1680,7 +1681,9 @@ report_computer(const char *filename, report_context * ctx, const char *bom)
}
}
report_crtypes(F, f->locale);
- write_translations(F);
+ if (f->locale!=crtag_locale()) {
+ report_translations(F);
+ }
reset_translations();
fclose(F);
return 0;
diff --git a/src/economy.c b/src/economy.c
index c210ee643..0bc056b56 100644
--- a/src/economy.c
+++ b/src/economy.c
@@ -468,7 +468,6 @@ static void recruit(unit * u, struct order *ord, request ** recruitorders)
assert(rc);
u_setrace(u, rc);
-#if GUARD_DISABLES_RECRUIT
/* this is a very special case because the recruiting unit may be empty
* at this point and we have to look at the creating unit instead. This
* is done in cansee, which is called indirectly by is_guarded(). */
@@ -476,13 +475,11 @@ static void recruit(unit * u, struct order *ord, request ** recruitorders)
cmistake(u, ord, 70, MSG_EVENT);
return;
}
-#endif
if (rc == get_race(RC_INSECT)) {
gamedate date;
get_gamedate(turn, &date);
if (date.season == 0 && r->terrain != newterrain(T_DESERT)) {
-#ifdef INSECT_POTION
bool usepotion = false;
unit *u2;
@@ -492,7 +489,6 @@ static void recruit(unit * u, struct order *ord, request ** recruitorders)
break;
}
if (!usepotion)
-#endif
{
cmistake(u, ord, 98, MSG_EVENT);
return;
@@ -579,7 +575,7 @@ void give_control(unit * u, unit * u2)
assert(u->building == u2->building);
if (f == u->faction) {
- building *b = largestbuilding(r, &cmp_current_owner, false);
+ building *b = largestbuilding(r, cmp_current_owner, false);
if (b == u->building) {
friendly_takeover(r, u2->faction);
}
@@ -802,40 +798,99 @@ void economics(region * r)
}
-/* ------------------------------------------------------------- */
+static void mod_skill(const resource_mod *mod, skill_t sk, int *skill) {
+ 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];
+ }
+}
+
+static struct message * get_modifiers(unit *u, skill_t sk, const resource_type *rtype, variant *savep, int *skillp) {
+ struct building *b = inside_building(u);
+ const struct building_type *btype = building_is_active(b) ? b->type : NULL;
+ int save_n = 1, save_d = 1;
+ int skill = 0;
+ int need_race = 0, need_bldg = 0;
+ resource_mod *mod;
+ const struct building_type *btype_needed = NULL;
+
+ if (btype && btype->modifiers) {
+ for (mod = btype->modifiers; mod && mod->type != RMT_END; ++mod) {
+ if (mod->type == RMT_PROD_SKILL) {
+ mod_skill(mod, sk, &skill);
+ }
+ }
+ }
+
+ for (mod = rtype->modifiers; mod && mod->type != RMT_END; ++mod) {
+ if (mod->btype == NULL || mod->btype == btype) {
+ if (mod->race == NULL || mod->race == u_race(u)) {
+ switch (mod->type) {
+ case RMT_PROD_SAVE:
+ if (savep) {
+ save_n *= mod->value.sa[0];
+ save_d *= mod->value.sa[1];
+ }
+ break;
+ case RMT_PROD_SKILL:
+ mod_skill(mod, sk, &skill);
+ break;
+ case RMT_PROD_REQUIRE:
+ if (mod->race) need_race |= 1;
+ if (mod->btype) {
+ need_bldg |= 1;
+ }
+ break;
+ default:
+ /* is not a production modifier, ignore it */
+ break;
+ }
+ }
+ }
+ if (mod->type == RMT_PROD_REQUIRE) {
+ if (mod->race) need_race |= 2;
+ if (mod->btype) {
+ btype_needed = mod->btype;
+ need_bldg |= 2;
+ }
+ }
+ }
+ if (need_race == 2) {
+ return msg_error(u, u->thisorder, 117);
+ }
+ if (btype_needed && need_bldg == 2) {
+ return msg_feedback(u, u->thisorder, "building_needed", "building", btype_needed->_name);
+ }
+ *skillp = skill;
+ if (savep) *savep = frac_make(save_n, save_d);
+ return NULL;
+}
static void manufacture(unit * u, const item_type * itype, int want)
{
int n;
- int skill;
int minskill = itype->construction->minskill;
skill_t sk = itype->construction->skill;
+ message *msg;
+ int skill_mod;
- skill = effskill(u, sk, 0);
- skill =
- skillmod(itype->rtype->attribs, u, u->region, sk, skill, SMF_PRODUCTION);
-
- if (skill < 0) {
- /* an error occured */
- int err = -skill;
- cmistake(u, u->thisorder, err, MSG_PRODUCE);
+ msg = get_modifiers(u, sk, itype->rtype, NULL, &skill_mod);
+ if (msg) {
+ ADDMSG(&u->faction->msgs, msg);
return;
}
if (want == 0) {
want = maxbuild(u, itype->construction);
}
- n = build(u, itype->construction, 0, want);
+ n = build(u, itype->construction, 0, want, skill_mod);
switch (n) {
case ENEEDSKILL:
ADDMSG(&u->faction->msgs,
msg_feedback(u, u->thisorder, "skill_needed", "skill", sk));
return;
- case EBUILDINGREQ:
- ADDMSG(&u->faction->msgs,
- msg_feedback(u, u->thisorder, "building_needed", "building",
- itype->construction->btype->_name));
- return;
case ELOWSKILL:
ADDMSG(&u->faction->msgs,
msg_feedback(u, u->thisorder, "manufacture_skills",
@@ -883,41 +938,6 @@ enum {
AFL_LOWSKILL = 1 << 1
};
-struct message * get_modifiers(unit *u, const resource_mod *mod, variant *savep, int *skillp) {
- struct building *b = inside_building(u);
- const struct building_type *btype = building_is_active(b) ? b->type : NULL;
- int save_n = 1, save_d = 1;
- int skill = 0;
-
- for (; mod->flags != 0; ++mod) {
- if (mod->btype == NULL || mod->btype == btype) {
- if (mod->race == NULL || mod->race == u_race(u)) {
- if (mod->flags & RMF_SAVEMATERIAL) {
- save_n *= mod->value.sa[0];
- save_d *= mod->value.sa[1];
- }
- if (mod->flags & RMF_SKILL) {
- skill += mod->value.i;
- }
- }
- } else if (mod->flags & RMF_REQUIREDBUILDING) {
- return msg_error(u, u->thisorder, 104);
- }
- }
- *skillp = skill;
- assert(save_n < SHRT_MAX);
- assert(save_n > SHRT_MIN);
- assert(save_d < SHRT_MAX);
- assert(save_d > SHRT_MIN);
- savep->sa[0] = (short)save_n;
- savep->sa[1] = (short)save_d;
- return NULL;
-}
-
-static resource_limit *get_resourcelimit(const resource_type *rtype) {
- return rtype->limit;
-}
-
static void allocate_resource(unit * u, const resource_type * rtype, int want)
{
const item_type *itype = resource2item(rtype);
@@ -925,19 +945,19 @@ static void allocate_resource(unit * u, const resource_type * rtype, int want)
int dm = 0;
allocation_list *alist;
allocation *al;
- resource_limit *rdata = get_resourcelimit(rtype);
const resource_type *rring;
int amount, skill, skill_mod = 0;
variant save_mod;
+ skill_t sk;
/* momentan kann man keine ressourcen abbauen, wenn man daf�r
* Materialverbrauch hat: */
assert(itype != NULL && (itype->construction == NULL
|| itype->construction->materials == NULL));
- assert(rdata != NULL);
- if (rdata->limit != NULL) {
- int avail = rdata->limit(r, rtype);
+ sk = itype->construction->skill;
+ if (!rtype->raw) {
+ int avail = limit_resource(r, rtype);
if (avail <= 0) {
cmistake(u, u->thisorder, 121, MSG_PRODUCE);
return;
@@ -949,8 +969,8 @@ static void allocate_resource(unit * u, const resource_type * rtype, int want)
return;
}
- if (rdata->modifiers) {
- message *msg = get_modifiers(u, rdata->modifiers, &save_mod, &skill_mod);
+ if (rtype->modifiers) {
+ message *msg = get_modifiers(u, sk, rtype, &save_mod, &skill_mod);
if (msg) {
ADDMSG(&u->faction->msgs, msg);
return;
@@ -978,17 +998,14 @@ static void allocate_resource(unit * u, const resource_type * rtype, int want)
}
}
- assert(itype->construction->skill != 0
- || "limited resource needs a required skill for making it");
- skill = effskill(u, itype->construction->skill, 0);
+ assert(sk != NOSKILL || "limited resource needs a required skill for making it");
+ skill = effskill(u, sk, 0);
if (skill == 0) {
- skill_t sk = itype->construction->skill;
add_message(&u->faction->msgs,
msg_feedback(u, u->thisorder, "skill_needed", "skill", sk));
return;
}
if (skill < itype->construction->minskill) {
- skill_t sk = itype->construction->skill;
add_message(&u->faction->msgs,
msg_feedback(u, u->thisorder, "manufacture_skills",
"skill minskill product", sk, itype->construction->minskill,
@@ -1126,17 +1143,17 @@ attrib_allocation(const resource_type * rtype, region * r, allocation * alist)
{
allocation *al;
int nreq = 0;
- resource_limit *rdata = get_resourcelimit(rtype);
int avail = INT_MAX;
for (al = alist; al; al = al->next) {
nreq += required(al->want, al->save);
}
- if (rdata->limit) {
- avail = rdata->limit(r, rtype);
- if (avail < 0)
+ if (!rtype->raw) {
+ avail = limit_resource(r, rtype);
+ if (avail < 0) {
avail = 0;
+ }
}
avail = MIN(avail, nreq);
@@ -1151,10 +1168,11 @@ attrib_allocation(const resource_type * rtype, region * r, allocation * alist)
nreq -= want;
al->get = x * al->save.sa[1] / al->save.sa[0];
al->get = MIN(al->want, al->get);
- if (rdata->produce) {
+ if (!rtype->raw) {
int use = required(al->get, al->save);
- if (use)
- rdata->produce(r, rtype, use);
+ if (use) {
+ produce_resource(r, rtype, use);
+ }
}
}
}
@@ -1166,21 +1184,15 @@ typedef void(*allocate_function) (const resource_type *, struct region *,
static allocate_function get_allocator(const struct resource_type *rtype)
{
- resource_limit *rdata = get_resourcelimit(rtype);
-
- if (rdata) {
- if (rdata->limit != NULL) {
- return attrib_allocation;
- }
+ if (rtype->raw) {
return leveled_allocation;
}
- return NULL;
+ return attrib_allocation;
}
void split_allocations(region * r)
{
allocation_list **p_alist = &allocations;
- freset(r, RF_SELECT);
while (*p_alist) {
allocation_list *alist = *p_alist;
const resource_type *rtype = alist->type;
@@ -1188,7 +1200,6 @@ void split_allocations(region * r)
const item_type *itype = resource2item(rtype);
allocation **p_al = &alist->data;
- freset(r, RF_SELECT);
alloc(rtype, r, alist->data);
while (*p_al) {
@@ -1197,7 +1208,6 @@ void split_allocations(region * r)
assert(itype || !"not implemented for non-items");
i_change(&al->unit->items, itype, al->get);
produceexp(al->unit, itype->construction->skill, al->unit->number);
- fset(r, RF_SELECT);
}
if (al->want == INT_MAX)
al->want = al->get;
@@ -1220,18 +1230,13 @@ static void create_potion(unit * u, const potion_type * ptype, int want)
if (want == 0) {
want = maxbuild(u, ptype->itype->construction);
}
- built = build(u, ptype->itype->construction, 0, want);
+ built = build(u, ptype->itype->construction, 0, want, 0);
switch (built) {
case ELOWSKILL:
case ENEEDSKILL:
/* no skill, or not enough skill points to build */
cmistake(u, u->thisorder, 50, MSG_PRODUCE);
break;
- case EBUILDINGREQ:
- ADDMSG(&u->faction->msgs,
- msg_feedback(u, u->thisorder, "building_needed", "building",
- ptype->itype->construction->btype->_name));
- break;
case ECOMPLETE:
assert(0);
break;
@@ -1255,12 +1260,10 @@ static void create_potion(unit * u, const potion_type * ptype, int want)
void make_item(unit * u, const item_type * itype, int want)
{
if (itype->construction && fval(itype->rtype, RTF_LIMITED)) {
-#if GUARD_DISABLES_PRODUCTION == 1
if (is_guarded(u->region, u)) {
cmistake(u, u->thisorder, 70, MSG_EVENT);
return;
}
-#endif
allocate_resource(u, itype->rtype, want);
}
else {
@@ -2033,20 +2036,6 @@ static void expandstealing(region * r, request * stealorders)
if (u && u->region == r) {
n = get_pooled(u, rsilver, GET_ALL, INT_MAX);
}
-#ifndef GOBLINKILL
- if (oa[i].type.goblin) { /* Goblin-Spezialklau */
- int uct = 0;
- unit *u2;
- assert(effskill(oa[i].unit, SK_STEALTH) >= 4
- || !"this goblin\'s skill is too low");
- for (u2 = r->units; u2; u2 = u2->next) {
- if (u2->faction == u->faction) {
- uct += maintenance_cost(u2);
- }
- }
- n -= uct * 2;
- }
-#endif
if (n > 10 && rplane(r) && (rplane(r)->flags & PFL_NOALLIANCES)) {
/* In Questen nur reduziertes Klauen */
n = 10;
@@ -2665,8 +2654,7 @@ expandwork(region * r, request * work_begin, request * work_end, int maxwork)
const curse_type *blessedharvest_ct = ct_find("blessedharvest");
if (blessedharvest_ct) {
int happy =
- (int)curse_geteffect(get_curse(r->attribs, blessedharvest_ct));
- happy = MIN(happy, jobs);
+ (int)(jobs * curse_geteffect(get_curse(r->attribs, blessedharvest_ct)));
earnings += happy;
}
}
@@ -2936,7 +2924,7 @@ static void peasant_taxes(region * r)
unit *u;
building *b;
int money;
- int maxsize;
+ int level;
f = region_get_owner(r);
if (f == NULL || is_mourning(r, turn)) {
@@ -2954,10 +2942,10 @@ static void peasant_taxes(region * r)
if (u == NULL || u->faction != f)
return;
- maxsize = buildingeffsize(b, false);
- if (maxsize > 0) {
- double taxfactor = money * b->type->taxes(b, maxsize);
- double morale = MORALE_TAX_FACTOR * money * region_get_morale(r);
+ level = buildingeffsize(b, false);
+ if (level > 0) {
+ double taxfactor = (double)money * level / building_taxes(b);
+ double morale = (double)money * region_get_morale(r) / MORALE_TAX_FACTOR;
if (taxfactor > morale) {
taxfactor = morale;
}
diff --git a/src/economy.test.c b/src/economy.test.c
index b77c69a86..802610880 100644
--- a/src/economy.test.c
+++ b/src/economy.test.c
@@ -316,8 +316,12 @@ static void test_recruit(CuTest *tc) {
f = test_create_faction(0);
u = test_create_unit(f, test_create_region(0, 0, 0));
CuAssertIntEquals(tc, 1, u->number);
+ CuAssertIntEquals(tc, 1, f->num_people);
+ CuAssertIntEquals(tc, 1, f->num_units);
add_recruits(u, 1, 1);
CuAssertIntEquals(tc, 2, u->number);
+ CuAssertIntEquals(tc, 2, f->num_people);
+ CuAssertIntEquals(tc, 1, f->num_units);
CuAssertPtrEquals(tc, u, f->units);
CuAssertPtrEquals(tc, NULL, u->nextF);
CuAssertPtrEquals(tc, NULL, u->prevF);
@@ -341,12 +345,118 @@ static void test_income(CuTest *tc)
test_cleanup();
}
-static void test_make_item(CuTest *tc) {
+static void test_modify_material(CuTest *tc) {
+ unit *u;
+ struct item_type *itype;
+ resource_type *rtype;
+ resource_mod *mod;
+
+ test_setup();
+ init_resources();
+
+ u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
+ set_level(u, SK_WEAPONSMITH, 1);
+
+ /* the unit's race gets 2x savings on iron used to produce goods */
+ itype = test_create_itemtype("iron");
+ rtype = itype->rtype;
+ mod = rtype->modifiers = calloc(2, sizeof(resource_mod));
+ mod[0].type = RMT_USE_SAVE;
+ mod[0].value = frac_make(2, 1);
+ mod[0].race = u_race(u);
+
+ itype = test_create_itemtype("sword");
+ make_item(u, itype, 1);
+ CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "error_cannotmake"));
+ CuAssertIntEquals(tc, 0, get_item(u, itype));
+ test_clear_messages(u->faction);
+ itype->construction = calloc(1, sizeof(construction));
+ itype->construction->skill = SK_WEAPONSMITH;
+ itype->construction->minskill = 1;
+ itype->construction->maxsize = 1;
+ itype->construction->reqsize = 1;
+ itype->construction->materials = calloc(2, sizeof(requirement));
+ itype->construction->materials[0].rtype = rtype;
+ itype->construction->materials[0].number = 2;
+
+ set_item(u, rtype->itype, 1); /* 1 iron should get us 1 sword */
+ make_item(u, itype, 1);
+ CuAssertIntEquals(tc, 1, get_item(u, itype));
+ CuAssertIntEquals(tc, 0, get_item(u, rtype->itype));
+
+ u_setrace(u, test_create_race("smurf"));
+ set_item(u, rtype->itype, 2); /* 2 iron should be required now */
+ make_item(u, itype, 1);
+ CuAssertIntEquals(tc, 2, get_item(u, itype));
+ CuAssertIntEquals(tc, 0, get_item(u, rtype->itype));
+
+ test_cleanup();
+}
+
+static void test_modify_skill(CuTest *tc) {
+ unit *u;
+ struct item_type *itype;
+ /* building_type *btype; */
+ resource_type *rtype;
+ resource_mod *mod;
+
+ test_setup();
+ init_resources();
+
+ u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
+ set_level(u, SK_WEAPONSMITH, 1);
+
+ itype = test_create_itemtype("iron");
+ rtype = itype->rtype;
+
+ itype = test_create_itemtype("sword");
+ make_item(u, itype, 1);
+ CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "error_cannotmake"));
+ CuAssertIntEquals(tc, 0, get_item(u, itype));
+ test_clear_messages(u->faction);
+ itype->construction = calloc(1, sizeof(construction));
+ itype->construction->skill = SK_WEAPONSMITH;
+ itype->construction->minskill = 1;
+ itype->construction->maxsize = -1;
+ itype->construction->reqsize = 1;
+ itype->construction->materials = calloc(2, sizeof(requirement));
+ itype->construction->materials[0].rtype = rtype;
+ itype->construction->materials[0].number = 1;
+
+ /* our race gets a +1 bonus to the item's production skill */
+ mod = itype->rtype->modifiers = calloc(2, sizeof(resource_mod));
+ mod[0].type = RMT_PROD_SKILL;
+ mod[0].value.sa[0] = SK_WEAPONSMITH;
+ mod[0].value.sa[1] = 1;
+ mod[0].race = u_race(u);
+
+ set_item(u, rtype->itype, 2); /* 2 iron should get us 2 swords */
+ make_item(u, itype, 2);
+ CuAssertIntEquals(tc, 2, get_item(u, itype));
+ CuAssertIntEquals(tc, 0, get_item(u, rtype->itype));
+
+ mod[0].value.sa[0] = NOSKILL; /* match any skill */
+ set_item(u, rtype->itype, 2);
+ make_item(u, itype, 2);
+ CuAssertIntEquals(tc, 4, get_item(u, itype));
+ CuAssertIntEquals(tc, 0, get_item(u, rtype->itype));
+
+
+ u_setrace(u, test_create_race("smurf"));
+ set_item(u, rtype->itype, 2);
+ make_item(u, itype, 1); /* only enough skill to make 1 now */
+ CuAssertIntEquals(tc, 5, get_item(u, itype));
+ CuAssertIntEquals(tc, 1, get_item(u, rtype->itype));
+
+ test_cleanup();
+}
+
+
+static void test_modify_production(CuTest *tc) {
unit *u;
struct item_type *itype;
const struct resource_type *rt_silver;
resource_type *rtype;
- resource_limit *rdata;
double d = 0.6;
test_setup();
@@ -380,8 +490,7 @@ static void test_make_item(CuTest *tc) {
itype->construction->materials = 0;
rtype->flags |= RTF_LIMITED;
rmt_create(rtype);
- rdata = rtype->limit = calloc(1, sizeof(resource_limit));
- add_resource(u->region, 1, 300, 150, rtype);
+ add_resource(u->region, 1, 300, 150, rtype); /* there are 300 stones at level 1 */
CuAssertIntEquals(tc, 300, region_getresource(u->region, rtype));
set_level(u, SK_ALCHEMY, 10);
@@ -390,11 +499,11 @@ static void test_make_item(CuTest *tc) {
CuAssertIntEquals(tc, 11, get_item(u, itype));
CuAssertIntEquals(tc, 290, region_getresource(u->region, rtype)); /* used 10 stones to make 10 stones */
- rdata->modifiers = calloc(2, sizeof(resource_mod));
- rdata->modifiers[0].flags = RMF_SAVEMATERIAL;
- rdata->modifiers[0].race = u->_race;
- rdata->modifiers[0].value.sa[0] = (short)(0.5+100*d);
- rdata->modifiers[0].value.sa[1] = 100;
+ rtype->modifiers = calloc(2, sizeof(resource_mod));
+ rtype->modifiers[0].type = RMT_PROD_SAVE;
+ rtype->modifiers[0].race = u->_race;
+ rtype->modifiers[0].value.sa[0] = (short)(0.5+100*d);
+ rtype->modifiers[0].value.sa[1] = 100;
make_item(u, itype, 10);
split_allocations(u->region);
CuAssertIntEquals(tc, 21, get_item(u, itype));
@@ -405,17 +514,39 @@ static void test_make_item(CuTest *tc) {
CuAssertIntEquals(tc, 22, get_item(u, itype));
CuAssertIntEquals(tc, 283, region_getresource(u->region, rtype)); /* no free lunches */
- rdata->modifiers[0].value = frac_make(1, 2);
+ rtype->modifiers[0].value = frac_make(1, 2);
make_item(u, itype, 6);
split_allocations(u->region);
CuAssertIntEquals(tc, 28, get_item(u, itype));
CuAssertIntEquals(tc, 280, region_getresource(u->region, rtype)); /* 50% saving = 3 stones make 6 stones */
- rdata->modifiers[0].flags = RMF_REQUIREDBUILDING;
- rdata->modifiers[0].race = NULL;
- rdata->modifiers[0].btype = bt_get_or_create("mine");
+ rtype->modifiers[0].type = RMT_PROD_REQUIRE;
+ rtype->modifiers[0].race = NULL;
+ rtype->modifiers[0].btype = bt_get_or_create("mine");
+
+ test_clear_messages(u->faction);
make_item(u, itype, 10);
- CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "error104"));
+ CuAssertIntEquals(tc, 28, get_item(u, itype));
+ CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "building_needed"));
+
+ rtype->modifiers[0].type = RMT_PROD_REQUIRE;
+ rtype->modifiers[0].race = test_create_race("smurf");
+ rtype->modifiers[0].btype = NULL;
+
+ test_clear_messages(u->faction);
+ make_item(u, itype, 10);
+ CuAssertIntEquals(tc, 28, get_item(u, itype));
+ CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "error117"));
+
+ rtype->modifiers[1].type = RMT_PROD_REQUIRE;
+ rtype->modifiers[1].race = u_race(u);
+ rtype->modifiers[1].btype = NULL;
+
+ test_clear_messages(u->faction);
+ make_item(u, itype, 10);
+ CuAssertPtrEquals(tc, NULL, u->faction->msgs);
+ split_allocations(u->region);
+ CuAssertIntEquals(tc, 38, get_item(u, itype));
test_cleanup();
}
@@ -426,7 +557,9 @@ CuSuite *get_economy_suite(void)
SUITE_ADD_TEST(suite, test_give_control_building);
SUITE_ADD_TEST(suite, test_give_control_ship);
SUITE_ADD_TEST(suite, test_income);
- SUITE_ADD_TEST(suite, test_make_item);
+ SUITE_ADD_TEST(suite, test_modify_production);
+ SUITE_ADD_TEST(suite, test_modify_skill);
+ SUITE_ADD_TEST(suite, test_modify_material);
SUITE_ADD_TEST(suite, test_steal_okay);
SUITE_ADD_TEST(suite, test_steal_ocean);
SUITE_ADD_TEST(suite, test_steal_nosteal);
diff --git a/src/eressea.c b/src/eressea.c
index 8001355f1..a9dddd130 100755
--- a/src/eressea.c
+++ b/src/eressea.c
@@ -8,9 +8,6 @@
#if MUSEUM_MODULE
#include
#endif
-#if ARENA_MODULE
-#include
-#endif
#include
#include
#include
@@ -73,13 +70,9 @@ void game_init(void)
register_spells();
register_names();
register_resources();
- register_buildings();
register_itemfunctions();
#if MUSEUM_MODULE
register_museum();
-#endif
-#if ARENA_MODULE
- register_arena();
#endif
wormholes_register();
diff --git a/src/give.c b/src/give.c
index b52168647..060ecbbb9 100644
--- a/src/give.c
+++ b/src/give.c
@@ -19,6 +19,7 @@
/* kernel includes */
#include
+#include
#include
#include
#include
@@ -169,17 +170,35 @@ int give_quota(const unit * src, const unit * dst, const item_type * type,
return n;
}
+static void
+give_horses(unit * s, const item_type * itype, int n)
+{
+ region *r = s->region;
+ if (r->land) {
+ rsethorses(r, rhorses(r) + n);
+ }
+}
+
+static void
+give_money(unit * s, const item_type * itype, int n)
+{
+ region *r = s->region;
+ if (r->land) {
+ rsetmoney(r, rmoney(r) + n);
+ }
+}
+
int
give_item(int want, const item_type * itype, unit * src, unit * dest,
struct order *ord)
{
short error = 0;
- int n, r;
+ int n, delta;
assert(itype != NULL);
n = get_pooled(src, item2resource(itype), GET_SLACK | GET_POOLED_SLACK, want);
n = MIN(want, n);
- r = n;
+ delta = n;
if (dest && src->faction != dest->faction
&& src->faction->age < GiveRestriction()) {
if (ord != NULL) {
@@ -200,18 +219,19 @@ struct order *ord)
else if (itype->flags & ITF_CURSED) {
error = 25;
}
- else if (itype->give == NULL || itype->give(src, dest, itype, n, ord) != 0) {
+ else {
int use = use_pooled(src, item2resource(itype), GET_SLACK, n);
+
if (use < n)
use +=
use_pooled(src, item2resource(itype), GET_POOLED_SLACK,
n - use);
if (dest) {
- r = give_quota(src, dest, itype, n);
- i_change(&dest->items, itype, r);
+ delta = give_quota(src, dest, itype, n);
+ i_change(&dest->items, itype, delta);
#ifdef RESERVE_GIVE
#ifdef RESERVE_DONATIONS
- change_reservation(dest, itype, r);
+ change_reservation(dest, itype, delta);
#else
if (src->faction == dest->faction) {
change_reservation(dest, item2resource(itype), r);
@@ -221,14 +241,23 @@ struct order *ord)
#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, r);
+ warden_add_give(src, dest, itype, delta);
}
#endif
- handle_event(dest->attribs, "receive", src);
}
- handle_event(src->attribs, "give", dest);
+ else {
+ /* return horses to the region */
+ if (itype->construction && itype->flags & ITF_ANIMAL) {
+ if (itype->construction->skill == SK_HORSE_TRAINING) {
+ give_horses(src, itype, n);
+ }
+ }
+ else if (itype->rtype == get_resourcetype(R_SILVER)) {
+ give_money(src, itype, n);
+ }
+ }
}
- add_give(src, dest, n, r, item2resource(itype), ord, error);
+ add_give(src, dest, n, delta, item2resource(itype), ord, error);
if (error)
return -1;
return 0;
@@ -502,6 +531,23 @@ void give_unit(unit * u, unit * u2, order * ord)
}
}
return;
+ } else {
+ int err = checkunitnumber(u2->faction, 1);
+ if (err) {
+ if (err == 1) {
+ ADDMSG(&u->faction->msgs,
+ msg_feedback(u, ord,
+ "too_many_units_in_alliance",
+ "allowed", rule_alliance_limit()));
+ }
+ else {
+ ADDMSG(&u->faction->msgs,
+ msg_feedback(u, ord,
+ "too_many_units_in_faction",
+ "allowed", rule_faction_limit()));
+ }
+ return;
+ }
}
if (!alliedunit(u2, u->faction, HELP_GIVE) && ucontact(u2, u) == 0) {
diff --git a/src/give.test.c b/src/give.test.c
index 1767dec36..33a9ebfd9 100644
--- a/src/give.test.c
+++ b/src/give.test.c
@@ -54,26 +54,12 @@ static void setup_give(struct give *env) {
}
}
-static void test_give_unit_to_peasants(CuTest * tc) {
- struct give env = { 0 };
- test_setup_ex(tc);
- env.f1 = test_create_faction(0);
- 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();
-}
-
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);
setup_give(&env);
- env.r->terrain = test_create_terrain("ocean", SEA_REGION);
config_set("rules.give.max_men", "0");
give_unit(env.src, env.dst, NULL);
CuAssertPtrEquals(tc, env.f1, env.src->faction);
@@ -88,7 +74,38 @@ static void test_give_unit(CuTest * tc) {
test_cleanup();
}
-static void test_give_unit_in_ocean(CuTest * tc) {
+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);
+ setup_give(&env);
+ CuAssertIntEquals(tc, 1, env.f1->num_units);
+ CuAssertIntEquals(tc, 1, env.f2->num_units);
+ config_set("rules.limit.faction", "1");
+ give_unit(env.src, env.dst, NULL);
+ CuAssertPtrEquals(tc, env.f1, env.src->faction);
+ CuAssertIntEquals(tc, 0, env.f2->newbies);
+ 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();
+}
+
+static void test_give_unit_to_peasants(CuTest * tc) {
+ struct give env = { 0 };
+ test_setup_ex(tc);
+ env.f1 = test_create_faction(0);
+ 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();
+}
+
+static void test_give_unit_to_ocean(CuTest * tc) {
struct give env = { 0 };
test_setup_ex(tc);
env.f1 = test_create_faction(0);
@@ -429,7 +446,8 @@ CuSuite *get_give_suite(void)
SUITE_ADD_TEST(suite, test_give_men_requires_contact);
SUITE_ADD_TEST(suite, test_give_men_not_to_self);
SUITE_ADD_TEST(suite, test_give_unit);
- SUITE_ADD_TEST(suite, test_give_unit_in_ocean);
+ SUITE_ADD_TEST(suite, test_give_unit_limits);
+ SUITE_ADD_TEST(suite, test_give_unit_to_ocean);
SUITE_ADD_TEST(suite, test_give_unit_to_peasants);
SUITE_ADD_TEST(suite, test_give_peasants);
SUITE_ADD_TEST(suite, test_give_herbs);
diff --git a/src/gmtool.c b/src/gmtool.c
index 3551c3436..674e139f7 100644
--- a/src/gmtool.c
+++ b/src/gmtool.c
@@ -26,9 +26,6 @@
#if MUSEUM_MODULE
#include
#endif
-#if ARENA_MODULE
-#include
-#endif
#include
#include
@@ -905,8 +902,8 @@ static void handlekey(state * st, int c)
new_players = read_newfactions(sbuffer);
}
cnormalize(&st->cursor, &nx, &ny);
- minpop = config_get_int("seed.population.min", 8);
- maxpop = config_get_int("seed.population.max", minpop);
+ minpop = config_get_int("editor.population.min", 8);
+ maxpop = config_get_int("editor.population.max", minpop);
if (maxpop > minpop) {
n = rng_int() % (maxpop - minpop) + minpop;
}
diff --git a/src/guard.c b/src/guard.c
index 55f189b6c..118ede5fc 100644
--- a/src/guard.c
+++ b/src/guard.c
@@ -112,7 +112,7 @@ static bool is_guardian_r(const unit * guard)
if (guard->building && rule_region_owners() && guard == building_owner(guard->building)) {
faction *owner = region_get_owner(guard->region);
if (owner == guard->faction) {
- building *bowner = largestbuilding(guard->region, &cmp_taxes, false);
+ building *bowner = largestbuilding(guard->region, cmp_taxes, false);
if (bowner == guard->building) {
return true;
}
diff --git a/src/helpers.c b/src/helpers.c
index e9502e075..7591dba9f 100644
--- a/src/helpers.c
+++ b/src/helpers.c
@@ -13,20 +13,25 @@ without prior permission by the authors of Eressea.
#include
#include "helpers.h"
#include "vortex.h"
+#include "alchemy.h"
#include
#include
#include
+#include
#include
#include
#include
#include
+#include
#include
+#include
#include
#include
#include
#include
+#include
#include
#include
#include
@@ -78,7 +83,7 @@ lua_giveitem(unit * s, unit * d, const item_type * itype, int n, struct order *o
return result;
}
-static int limit_resource(const region * r, const resource_type * rtype)
+static int limit_resource_lua(const region * r, const resource_type * rtype)
{
char fname[64];
int result = -1;
@@ -110,7 +115,7 @@ static int limit_resource(const region * r, const resource_type * rtype)
}
static void
-produce_resource(region * r, const resource_type * rtype, int norders)
+produce_resource_lua(region * r, const resource_type * rtype, int norders)
{
lua_State *L = (lua_State *)global.vm_state;
char fname[64];
@@ -154,23 +159,12 @@ static void push_param(lua_State * L, char c, spllprm * param)
}
/** callback to use lua for spell functions */
-static int lua_callspell(castorder * co)
+static int lua_callspell(castorder * co, const char *fname)
{
lua_State *L = (lua_State *)global.vm_state;
- const char *fname = co->sp->sname;
unit *caster = co_get_caster(co);
region * r = co_get_region(co);
int result = -1;
- const char *hashpos = strchr(fname, '#');
- char fbuf[64];
-
- if (hashpos != NULL) {
- ptrdiff_t len = hashpos - fname;
- assert(len < (ptrdiff_t) sizeof(fbuf));
- memcpy(fbuf, fname, len);
- fbuf[len] = '\0';
- fname = fbuf;
- }
lua_getglobal(L, fname);
if (lua_isfunction(L, -1)) {
@@ -217,43 +211,6 @@ static int lua_callspell(castorder * co)
return result;
}
-/** callback to initialize a familiar from lua. */
-static int lua_initfamiliar(unit * u)
-{
- lua_State *L = (lua_State *)global.vm_state;
- char fname[64];
- int result = -1;
-
- strlcpy(fname, "initfamiliar_", sizeof(fname));
- strlcat(fname, u_race(u)->_name, sizeof(fname));
-
- lua_getglobal(L, fname);
- if (lua_isfunction(L, -1)) {
- tolua_pushusertype(L, u, TOLUA_CAST "unit");
-
- if (lua_pcall(L, 1, 1, 0) != 0) {
- const char *error = lua_tostring(L, -1);
- log_error("familiar(%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 {
- log_warning("familiar(%s) calling '%s': not a function.\n", unitname(u), fname);
- lua_pop(L, 1);
- }
-
- create_mage(u, M_GRAY);
-
- strlcpy(fname, u_race(u)->_name, sizeof(fname));
- strlcat(fname, "_familiar", sizeof(fname));
- equip_unit(u, get_equipment(fname));
- return result;
-}
-
static int
lua_changeresource(unit * u, const struct resource_type *rtype, int delta)
{
@@ -287,219 +244,23 @@ lua_changeresource(unit * u, const struct resource_type *rtype, int delta)
return result;
}
-static int lua_getresource(unit * u, const struct resource_type *rtype)
-{
- lua_State *L = (lua_State *)global.vm_state;
- int result = -1;
- char fname[64];
-
- strlcpy(fname, rtype->_name, sizeof(fname));
- strlcat(fname, "_getresource", sizeof(fname));
-
- lua_getglobal(L, fname);
- if (lua_isfunction(L, -1)) {
- tolua_pushusertype(L, u, TOLUA_CAST "unit");
-
- if (lua_pcall(L, 1, 1, 0) != 0) {
- const char *error = lua_tostring(L, -1);
- log_error("get(%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 {
- log_error("get(%s) calling '%s': not a function.\n", unitname(u), fname);
- lua_pop(L, 1);
- }
-
- return result;
-}
-
-static bool lua_canuse_item(const unit * u, const struct item_type *itype)
-{
- bool result = true;
- lua_State *L = (lua_State *)global.vm_state;
- const char *fname = "item_canuse";
-
- lua_getglobal(L, fname);
- if (lua_isfunction(L, -1)) {
- tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit");
- tolua_pushstring(L, itype->rtype->_name);
-
- if (lua_pcall(L, 2, 1, 0) != 0) {
- const char *error = lua_tostring(L, -1);
- log_error("use(%s) calling '%s': %s.\n", unitname(u), fname, error);
- lua_pop(L, 1);
- }
- else {
- result = lua_toboolean(L, -1);
- lua_pop(L, 1);
- }
- }
- else {
- log_error("use(%s) calling '%s': not a function.\n", unitname(u), fname);
- lua_pop(L, 1);
- }
- return result;
-}
-
-static int
-lua_wage(const region * r, const faction * f, const race * rc, int in_turn)
-{
- lua_State *L = (lua_State *)global.vm_state;
- const char *fname = "wage";
- int result = -1;
-
- lua_getglobal(L, fname);
- if (lua_isfunction(L, -1)) {
- tolua_pushusertype(L, (void *)r, TOLUA_CAST "region");
- tolua_pushusertype(L, (void *)f, TOLUA_CAST "faction");
- tolua_pushstring(L, rc ? rc->_name : 0);
- lua_pushinteger(L, in_turn);
-
- if (lua_pcall(L, 3, 1, 0) != 0) {
- const char *error = lua_tostring(L, -1);
- log_error("wage(%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 {
- log_error("wage(%s) calling '%s': not a function.\n", regionname(r, NULL), fname);
- lua_pop(L, 1);
- }
-
- return result;
-}
-
-static void lua_agebuilding(building * b)
-{
- lua_State *L = (lua_State *)global.vm_state;
- char fname[64];
-
- strlcpy(fname, "age_", sizeof(fname));
- strlcat(fname, b->type->_name, sizeof(fname));
-
- lua_getglobal(L, fname);
- if (lua_isfunction(L, -1)) {
- tolua_pushusertype(L, (void *)b, TOLUA_CAST "building");
-
- if (lua_pcall(L, 1, 0, 0) != 0) {
- const char *error = lua_tostring(L, -1);
- log_error("agebuilding(%s) calling '%s': %s.\n", buildingname(b), fname, error);
- lua_pop(L, 1);
- }
- }
- else {
- log_error("agebuilding(%s) calling '%s': not a function.\n", buildingname(b), fname);
- lua_pop(L, 1);
- }
-}
-
-static double lua_building_taxes(building * b, int level)
-{
- lua_State *L = (lua_State *)global.vm_state;
- const char *fname = "building_taxes";
- double result = 0.0F;
-
- lua_getglobal(L, fname);
- if (lua_isfunction(L, -1)) {
- tolua_pushusertype(L, (void *)b, TOLUA_CAST "building");
- lua_pushinteger(L, level);
-
- if (lua_pcall(L, 2, 1, 0) != 0) {
- const char *error = lua_tostring(L, -1);
- log_error("building_taxes(%s) calling '%s': %s.\n", buildingname(b), fname, error);
- lua_pop(L, 1);
- }
- else {
- result = (double)lua_tonumber(L, -1);
- lua_pop(L, 1);
- }
- }
- else {
- log_error("building_taxes(%s) calling '%s': not a function.\n", buildingname(b), fname);
- lua_pop(L, 1);
- }
- return result;
-}
-
-static int lua_maintenance(const unit * u)
-{
- lua_State *L = (lua_State *)global.vm_state;
- const char *fname = "maintenance";
- int result = -1;
-
- lua_getglobal(L, fname);
- if (lua_isfunction(L, -1)) {
- tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit");
-
- if (lua_pcall(L, 1, 1, 0) != 0) {
- const char *error = lua_tostring(L, -1);
- log_error("maintenance(%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 {
- log_error("maintenance(%s) calling '%s': not a function.\n", unitname(u), fname);
- lua_pop(L, 1);
- }
-
- return result;
-}
-
-static int lua_equipmentcallback(const struct equipment *eq, unit * u)
-{
- lua_State *L = (lua_State *)global.vm_state;
- char fname[64];
- int result = -1;
-
- strlcpy(fname, "equip_", sizeof(fname));
- strlcat(fname, eq->name, sizeof(fname));
-
- lua_getglobal(L, fname);
- if (lua_isfunction(L, -1)) {
- tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit");
-
- if (lua_pcall(L, 1, 1, 0) != 0) {
- const char *error = lua_tostring(L, -1);
- log_error("equip(%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 {
- log_error("equip(%s) calling '%s': not a function.\n", unitname(u), fname);
- lua_pop(L, 1);
- }
- return result;
-}
-
/** callback for an item-use function written in lua. */
-int
-lua_useitem(struct unit *u, const struct item_type *itype, int amount,
-struct order *ord)
+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;
char fname[64];
+ int (*callout)(unit *, const item_type *, int, struct order *);
strlcpy(fname, "use_", sizeof(fname));
strlcat(fname, itype->rtype->_name, sizeof(fname));
+ callout = (int(*)(unit *, const item_type *, int, struct order *))get_function(fname);
+ if (callout) {
+ return callout(u, itype, amount, ord);
+ }
+
lua_getglobal(L, fname);
if (lua_isfunction(L, -1)) {
tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit");
@@ -515,58 +276,44 @@ struct order *ord)
result = (int)lua_tonumber(L, -1);
lua_pop(L, 1);
}
+ return result;
}
- else {
- log_error("use(%s) calling '%s': not a function.\n", unitname(u), fname);
- lua_pop(L, 1);
+ lua_pop(L, 1);
+ if (itype->rtype->ptype) {
+ 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;
}
-int tolua_toid(lua_State * L, int idx, int def)
+/* compat code for old data files */
+static int caldera_read(trigger *t, struct gamedata *data)
{
- int no = 0;
- int type = lua_type(L, idx);
- if (type == LUA_TNUMBER) {
- no = (int)tolua_tonumber(L, idx, def);
- }
- else {
- const char *str = tolua_tostring(L, idx, NULL);
- no = str ? atoi36(str) : def;
- }
- return no;
+ UNUSED_ARG(t);
+ read_building_reference(data);
+ return AT_READ_FAIL;
}
+struct trigger_type tt_caldera = {
+ "caldera",
+ NULL, NULL, NULL, NULL,
+ caldera_read
+};
+
void register_tolua_helpers(void)
{
+ tt_register(&tt_caldera);
at_register(&at_direction);
at_register(&at_building_action);
- register_function((pf_generic)lua_building_taxes,
- TOLUA_CAST "lua_building_taxes");
- register_function((pf_generic)lua_agebuilding,
- TOLUA_CAST "lua_agebuilding");
- register_function((pf_generic)lua_callspell, TOLUA_CAST "lua_castspell");
- register_function((pf_generic)lua_initfamiliar,
- TOLUA_CAST "lua_initfamiliar");
- register_item_use(&lua_useitem, TOLUA_CAST "lua_useitem");
- register_function((pf_generic)lua_getresource,
- TOLUA_CAST "lua_getresource");
- register_function((pf_generic)lua_canuse_item,
- TOLUA_CAST "lua_canuse_item");
- register_function((pf_generic)lua_changeresource,
- TOLUA_CAST "lua_changeresource");
- register_function((pf_generic)lua_equipmentcallback,
- TOLUA_CAST "lua_equip");
+ callbacks.cast_spell = lua_callspell;
+ callbacks.use_item = use_item_lua;
+ callbacks.produce_resource = produce_resource_lua;
+ callbacks.limit_resource = limit_resource_lua;
- register_function((pf_generic)lua_wage, TOLUA_CAST "lua_wage");
- register_function((pf_generic)lua_maintenance,
- TOLUA_CAST "lua_maintenance");
-
- register_function((pf_generic)produce_resource,
- TOLUA_CAST "lua_produceresource");
- register_function((pf_generic)limit_resource,
- TOLUA_CAST "lua_limitresource");
- register_item_give(lua_giveitem, TOLUA_CAST "lua_giveitem");
+ register_function((pf_generic)lua_changeresource, "lua_changeresource");
+ register_item_give(lua_giveitem, "lua_giveitem");
}
diff --git a/src/helpers.h b/src/helpers.h
index d77765187..d0bbcc58b 100644
--- a/src/helpers.h
+++ b/src/helpers.h
@@ -14,9 +14,9 @@ without prior permission by the authors of Eressea.
extern "C" {
#endif
- struct lua_State;
- void register_tolua_helpers(void);
- int tolua_toid(struct lua_State *L, int idx, int def);
+ struct lua_State;
+
+ void register_tolua_helpers(void);
#ifdef __cplusplus
}
diff --git a/src/items.c b/src/items.c
index bb5009038..0f97ea675 100644
--- a/src/items.c
+++ b/src/items.c
@@ -1,6 +1,7 @@
#include
#include "items.h"
+#include "alchemy.h"
#include "study.h"
#include "economy.h"
#include "move.h"
@@ -14,16 +15,24 @@
#include
#include
#include
+#include
#include
#include
#include
#include
-#include
+#include
+
+/* triggers includes */
+#include
+#include
#include
+#include
+#include
#include
#include
+#include
#include
#include
@@ -34,7 +43,7 @@ static int
use_studypotion(struct unit *u, const struct item_type *itype, int amount,
struct order *ord)
{
- if (init_order(u->thisorder) == K_STUDY) {
+ if (u->thisorder && init_order(u->thisorder) == K_STUDY) {
char token[128];
skill_t sk = NOSKILL;
skill *sv = 0;
@@ -61,9 +70,9 @@ struct order *ord)
if (amount > MAXGAIN) {
amount = MAXGAIN;
}
- teach->value += amount * 30;
- if (teach->value > MAXGAIN * 30) {
- teach->value = MAXGAIN * 30;
+ teach->value += amount * STUDYDAYS;
+ if (teach->value > MAXGAIN * STUDYDAYS) {
+ teach->value = MAXGAIN * STUDYDAYS;
}
i_change(&u->items, itype, -amount);
return 0;
@@ -71,7 +80,6 @@ struct order *ord)
}
return EUNUSABLE;
}
-
/* END studypotion */
/* BEGIN speedsail */
@@ -89,9 +97,8 @@ struct order *ord)
}
effect = SPEEDSAIL_EFFECT;
- c =
- create_curse(u, &sh->attribs, ct_find("shipspeedup"), 20, INT_MAX, effect,
- 0);
+ c = create_curse(u, &sh->attribs, ct_find("shipspeedup"), 20, INT_MAX,
+ effect, 0);
c_setflag(c, CURSE_NOAGE);
ADDMSG(&u->faction->msgs, msg_message("use_speedsail", "unit speed", u,
@@ -125,15 +132,15 @@ struct order *ord)
UNUSED_ARG(ord);
assert(sp);
- /* Reduziert die Strke jedes Spruchs um effect */
+ /* Reduziert die St�rke jedes Spruchs um effect */
effect = 5;
- /* Hlt Sprche bis zu einem summierten Gesamtlevel von power aus.
+ /* H�lt Spr�che bis zu einem summierten Gesamtlevel von power aus.
* Jeder Zauber reduziert die 'Lebenskraft' (vigour) der Antimagiezone
* um seine Stufe */
force = effect * 20; /* Stufe 5 =~ 100 */
- /* Regionszauber auflsen */
+ /* Regionszauber aufl�sen */
while (*ap && force > 0) {
curse *c;
attrib *a = *ap;
@@ -145,7 +152,7 @@ struct order *ord)
}
c = (curse *)a->data.v;
- /* Immunitt prfen */
+ /* Immunit�t pr�fen */
if (c_flags(c) & CURSE_IMMUNE) {
do {
ap = &(*ap)->next;
@@ -171,52 +178,8 @@ struct order *ord)
return 0;
}
-static int
-use_instantartsculpture(struct unit *u, const struct item_type *itype,
-int amount, struct order *ord)
-{
- building *b;
-
- if (u->region->land == NULL) {
- ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_onlandonly", ""));
- return -1;
- }
-
- b = new_building(bt_find("artsculpture"), u->region, u->faction->locale);
- b->size = 100;
-
- ADDMSG(&u->region->msgs, msg_message("artsculpture_create", "unit region",
- u, u->region));
-
- use_pooled(u, itype->rtype, GET_DEFAULT, 1);
-
- return 0;
-}
-
-static int
-use_instantartacademy(struct unit *u, const struct item_type *itype,
-int amount, struct order *ord)
-{
- building *b;
-
- if (u->region->land == NULL) {
- ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_onlandonly", ""));
- return -1;
- }
-
- b = new_building(bt_find("artacademy"), u->region, u->faction->locale);
- b->size = 100;
-
- ADDMSG(&u->region->msgs, msg_message("artacademy_create", "unit region", u,
- u->region));
-
- use_pooled(u, itype->rtype, GET_DEFAULT, 1);
-
- return 0;
-}
-
-#define BAGPIPEFRACTION dice_rand("2d4+2")
-#define BAGPIPEDURATION dice_rand("2d10+4")
+#define BAGPIPEFRACTION (dice(2,4)+2)
+#define BAGPIPEDURATION (dice(2,10)+4)
static int
use_bagpipeoffear(struct unit *u, const struct item_type *itype,
@@ -264,14 +227,204 @@ int amount, struct order *ord)
return 0;
}
+static int
+use_birthdayamulet(unit * u, const struct item_type *itype, int amount,
+struct order *ord)
+{
+ direction_t d;
+ message *msg = msg_message("meow", "");
+
+ UNUSED_ARG(ord);
+ UNUSED_ARG(amount);
+ UNUSED_ARG(itype);
+
+ add_message(&u->region->msgs, msg);
+ for (d = 0; d < MAXDIRECTIONS; d++) {
+ region *tr = rconnect(u->region, d);
+ if (tr)
+ add_message(&tr->msgs, msg);
+ }
+ msg_release(msg);
+ return 0;
+}
+
+static int use_foolpotion(unit *u, const item_type *itype, int amount,
+ struct order *ord)
+{
+ int targetno = read_unitid(u->faction, u->region);
+ unit *target = findunit(targetno);
+ if (target == NULL || u->region != target->region) {
+ ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found",
+ ""));
+ return ECUSTOM;
+ }
+ if (effskill(u, SK_STEALTH, 0) <= effskill(target, SK_PERCEPTION, 0)) {
+ cmistake(u, ord, 64, MSG_EVENT);
+ return ECUSTOM;
+ }
+ ADDMSG(&u->faction->msgs, msg_message("givedumb",
+ "unit recipient amount", u, target, amount));
+
+ change_effect(target, itype->rtype->ptype, amount);
+ use_pooled(u, itype->rtype, GET_DEFAULT, amount);
+ return 0;
+}
+
+static int
+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);
+ }
+ else {
+ const race *irace = u_irace(u);
+ if (irace == u_race(u)) {
+ const race *rcfailure = rc_find("smurf");
+ if (!rcfailure) {
+ rcfailure = rc_find("toad");
+ }
+ if (rcfailure) {
+ trigger *trestore = trigger_changerace(u, u_race(u), irace);
+ if (trestore) {
+ int duration = 2 + rng_int() % 8;
+
+ add_trigger(&u->attribs, "timer", trigger_timeout(duration,
+ trestore));
+ u->irace = NULL;
+ u_setrace(u, rcfailure);
+ }
+ }
+ }
+ }
+ use_pooled(u, itype->rtype, GET_SLACK | GET_RESERVE | GET_POOLED_SLACK,
+ amount);
+ usetpotionuse(u, itype->rtype->ptype);
+
+ ADDMSG(&u->faction->msgs, msg_message("usepotion",
+ "unit potion", u, itype->rtype));
+ return 0;
+}
+
+static int heal(unit * user, int effect)
+{
+ int req = unit_max_hp(user) * user->number - user->hp;
+ if (req > 0) {
+ req = MIN(req, effect);
+ effect -= req;
+ user->hp += req;
+ }
+ return effect;
+}
+
+static int
+use_healingpotion(struct unit *user, const struct item_type *itype, int amount,
+struct order *ord)
+{
+ int effect = amount * 400;
+ unit *u = user->region->units;
+ effect = heal(user, effect);
+ while (effect > 0 && u != NULL) {
+ if (u->faction == user->faction) {
+ effect = heal(u, effect);
+ }
+ u = u->next;
+ }
+ use_pooled(user, itype->rtype, GET_SLACK | GET_RESERVE | GET_POOLED_SLACK,
+ amount);
+ usetpotionuse(user, itype->rtype->ptype);
+
+ ADDMSG(&user->faction->msgs, msg_message("usepotion",
+ "unit potion", user, itype->rtype));
+ return 0;
+}
+
+/* ------------------------------------------------------------- */
+/* Kann auch von Nichtmagier benutzt werden, modifiziert Taktik fuer diese
+* Runde um -1 - 4 Punkte. */
+static int
+use_tacticcrystal(unit * u, const struct item_type *itype, int amount,
+ struct order *ord)
+{
+ int i;
+ for (i = 0; i != amount; ++i) {
+ int duration = 1; /* wirkt nur in dieser Runde */
+ curse *c;
+ float effect;
+ float power = 5; /* Widerstand gegen Antimagiesprueche, ist in diesem
+ Fall egal, da der curse fuer den Kampf gelten soll,
+ der vor den Antimagiezaubern passiert */
+
+ effect = (float)(rng_int() % 6 - 1);
+ c = create_curse(u, &u->attribs, ct_find("skillmod"), power,
+ duration, effect, u->number);
+ c->data.i = SK_TACTICS;
+ UNUSED_ARG(ord);
+ }
+ use_pooled(u, itype->rtype, GET_DEFAULT, amount);
+ ADDMSG(&u->faction->msgs, msg_message("use_tacticcrystal",
+ "unit region", u, u->region));
+ return 0;
+}
+
+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;
+ }
+ 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;
+}
+
+static int use_warmthpotion(unit *u, const item_type *itype,
+ int amount, struct order *ord)
+{
+ if (u->faction->race == get_race(RC_INSECT)) {
+ u->flags |= UFL_WARMTH;
+ }
+ else {
+ /* nur fuer insekten: */
+ cmistake(u, ord, 163, MSG_EVENT);
+ return ECUSTOM;
+ }
+ use_pooled(u, itype->rtype, GET_SLACK | GET_RESERVE | GET_POOLED_SLACK,
+ amount);
+ usetpotionuse(u, itype->rtype->ptype);
+
+ ADDMSG(&u->faction->msgs, msg_message("usepotion",
+ "unit potion", u, itype->rtype));
+ return 0;
+}
+
void register_itemfunctions(void)
{
- register_demonseye();
- register_item_use(use_antimagiccrystal, "use_antimagiccrystal");
- register_item_use(use_instantartsculpture, "use_instantartsculpture");
+ /* have tests: */
+ register_item_use(use_mistletoe, "use_mistletoe");
+ register_item_use(use_tacticcrystal, "use_dreameye");
register_item_use(use_studypotion, "use_studypotion");
+ register_item_use(use_antimagiccrystal, "use_antimagic");
register_item_use(use_speedsail, "use_speedsail");
- register_item_use(use_instantartacademy, "use_instantartacademy");
register_item_use(use_bagpipeoffear, "use_bagpipeoffear");
register_item_use(use_aurapotion50, "use_aurapotion50");
+ register_item_use(use_birthdayamulet, "use_aoc");
+ register_item_use(use_foolpotion, "use_p7");
+ register_item_use(use_bloodpotion, "use_peasantblood");
+ register_item_use(use_healingpotion, "use_ointment");
+ register_item_use(use_warmthpotion, "use_nestwarmth");
+
+ /* ungetestet: Wasser des Lebens */
+ register_item_use(use_potion_delayed, "use_p2");
}
diff --git a/src/items/CMakeLists.txt b/src/items/CMakeLists.txt
index bbf192a66..37777f9e4 100644
--- a/src/items/CMakeLists.txt
+++ b/src/items/CMakeLists.txt
@@ -5,7 +5,6 @@ xerewards.test.c
)
SET(_FILES
-demonseye.c
speedsail.c
weapons.c
xerewards.c
diff --git a/src/items/demonseye.c b/src/items/demonseye.c
deleted file mode 100644
index 563a16047..000000000
--- a/src/items/demonseye.c
+++ /dev/null
@@ -1,65 +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 "demonseye.h"
-
-/* kernel includes */
-#include
-#include
-#include
-#include
-#include
-#include
-
-/* util includes */
-#include
-
-/* libc includes */
-#include
-
-static int
-summon_igjarjuk(struct unit *u, const struct item_type *itype, int amount,
-struct order *ord)
-{
- struct plane *p = rplane(u->region);
- UNUSED_ARG(amount);
- UNUSED_ARG(itype);
- if (p != NULL) {
- ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "use_realworld_only", ""));
- return EUNUSABLE;
- }
- else {
- assert(!"not implemented");
- return EUNUSABLE;
- }
-}
-
-static int
-give_igjarjuk(struct unit *src, struct unit *d, const struct item_type *itype,
-int n, struct order *ord)
-{
- ADDMSG(&src->faction->msgs, msg_feedback(src, ord, "error_giveeye", ""));
- return 0;
-}
-
-void register_demonseye(void)
-{
- register_item_use(summon_igjarjuk, "useigjarjuk");
- register_item_give(give_igjarjuk, "giveigjarjuk");
-}
diff --git a/src/items/demonseye.h b/src/items/demonseye.h
deleted file mode 100644
index 8d878a174..000000000
--- a/src/items/demonseye.h
+++ /dev/null
@@ -1,30 +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_ITM_DEMONSEYE
-#define H_ITM_DEMONSEYE
-#ifdef __cplusplus
-extern "C" {
-#endif
-
- void register_demonseye(void);
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/src/kernel/CMakeLists.txt b/src/kernel/CMakeLists.txt
index d3a2e8e56..fe560af7a 100644
--- a/src/kernel/CMakeLists.txt
+++ b/src/kernel/CMakeLists.txt
@@ -6,6 +6,7 @@ alliance.test.c
ally.test.c
build.test.c
building.test.c
+# callbacks.test.c
command.test.c
config.test.c
# connection.test.c
@@ -16,7 +17,7 @@ group.test.c
item.test.c
messages.test.c
order.test.c
-# pathdinder.test.c
+# pathfinder.test.c
plane.test.c
pool.test.c
race.test.c
@@ -38,6 +39,7 @@ alliance.c
ally.c
build.c
building.c
+callbacks.c
command.c
config.c
connection.c
@@ -54,6 +56,7 @@ pool.c
race.c
region.c
resources.c
+rules.c
save.c
ship.c
skills.c
diff --git a/src/kernel/alliance.c b/src/kernel/alliance.c
index 0feb8407d..910670d10 100644
--- a/src/kernel/alliance.c
+++ b/src/kernel/alliance.c
@@ -239,8 +239,25 @@ static void perform_transfer(void)
}
}
+bool num_units_cb(void *entry, void *more) {
+ faction *f = (faction *)entry;
+ int *num = (int *)more;
+ *num += f->num_units;
+ return true;
+}
+
+int alliance_size(const alliance *al)
+{
+ int num = 0;
+ if (al) {
+ selist_foreach_ex(al->members, num_units_cb, &num);
+ }
+ return num;
+}
+
static void perform_join(void)
{
+ int alimit = rule_alliance_limit();
alliance_transaction **tap = transactions + ALLIANCE_JOIN;
while (*tap) {
alliance_transaction *ta = *tap;
@@ -270,7 +287,16 @@ static void perform_join(void)
ti = *tip;
}
if (ti) {
- setalliance(fj, al);
+ int maxsize = (alimit > 0) ? (alimit - alliance_size(al)) : 0;
+ if (alimit > 0 && fj->num_units > maxsize) {
+ ADDMSG(&fj->msgs,
+ msg_feedback(ta->u, ta->ord,
+ "too_many_units_in_alliance",
+ "allowed", alimit));
+ }
+ else {
+ setalliance(fj, al);
+ }
*tip = ti->next;
free(ti);
}
diff --git a/src/kernel/alliance.h b/src/kernel/alliance.h
index 8e112e8c9..00b4b29e4 100644
--- a/src/kernel/alliance.h
+++ b/src/kernel/alliance.h
@@ -67,7 +67,7 @@ extern "C" {
struct faction *alliance_get_leader(struct alliance *al);
void alliance_cmd(void);
bool is_allied(const struct faction *f1, const struct faction *f2);
-
+ int alliance_size(const struct alliance *al); /* #units in the alliance */
void alliance_setname(alliance * self, const char *name);
/* execute commands */
diff --git a/src/kernel/alliance.test.c b/src/kernel/alliance.test.c
index f63767672..885bc8413 100644
--- a/src/kernel/alliance.test.c
+++ b/src/kernel/alliance.test.c
@@ -112,6 +112,29 @@ static void test_alliance_cmd(CuTest *tc) {
test_cleanup();
}
+static void test_alliance_limits(CuTest *tc) {
+ unit *u1, *u2;
+ 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);
+
+ config_set("rules.limit.alliance", "1");
+ 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)));
+ CuAssertTrue(tc, !is_allied(u1->faction, u2->faction));
+ CuAssertPtrEquals(tc, 0, f_get_alliance(u1->faction));
+ alliance_cmd();
+ CuAssertPtrNotNull(tc, f_get_alliance(u1->faction));
+ 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();
+}
+
static void test_alliance_cmd_kick(CuTest *tc) {
unit *u1, *u2;
struct region *r;
@@ -200,6 +223,7 @@ CuSuite *get_alliance_suite(void)
SUITE_ADD_TEST(suite, test_alliance_dead_faction);
SUITE_ADD_TEST(suite, test_alliance_make);
SUITE_ADD_TEST(suite, test_alliance_join);
+ SUITE_ADD_TEST(suite, test_alliance_limits);
SUITE_ADD_TEST(suite, test_alliance_cmd);
SUITE_ADD_TEST(suite, test_alliance_cmd_no_invite);
SUITE_ADD_TEST(suite, test_alliance_cmd_kick);
diff --git a/src/kernel/build.c b/src/kernel/build.c
index 88ab35fd2..57c172905 100644
--- a/src/kernel/build.c
+++ b/src/kernel/build.c
@@ -43,6 +43,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include
#include
#include
+#include
#include
#include
#include
@@ -67,9 +68,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include
#include
-/* attributes inclues */
-#include
-
struct building *getbuilding(const struct region *r)
{
building *b = findbuilding(getid());
@@ -404,16 +402,26 @@ static int required(int size, int msize, int maxneed)
return used;
}
-static int
-matmod(const attrib * a, const unit * u, const resource_type * material,
-int value)
+static int matmod(const unit * u, const resource_type * rtype, int value)
{
- for (a = a_find((attrib *)a, &at_matmod); a && a->type == &at_matmod;
- a = a->next) {
- mm_fun fun = (mm_fun)a->data.f;
- value = fun(u, material, value);
- if (value < 0)
- return value; /* pass errors to caller */
+ if (rtype->modifiers) {
+ variant save = frac_make(1, 1);
+ const struct building_type *btype = NULL;
+ const struct race *rc = u_race(u);
+ resource_mod *mod;
+ if (u->building && inside_building(u)) {
+ btype = u->building->type;
+ }
+ for (mod = rtype->modifiers; mod->type != RMT_END; ++mod) {
+ if (mod->type == RMT_USE_SAVE) {
+ if (!mod->btype || mod->btype == btype) {
+ if (!mod->race || mod->race == rc) {
+ save = frac_mul(save, mod->value);
+ }
+ }
+ }
+ }
+ return value * save.sa[0] / save.sa[1];
}
return value;
}
@@ -439,14 +447,8 @@ static int use_materials(unit *u, const construction *type, int n, int completed
required(completed + n, type->reqsize, type->materials[c].number);
int multi = 1;
int canuse = 100; /* normalization */
- if (building_is_active(u->building) && inside_building(u)) {
- canuse = matmod(u->building->type->attribs, u, rtype, canuse);
- }
- if (canuse < 0) {
- return canuse; /* pass errors to caller */
- }
- canuse = matmod(type->attribs, u, rtype, canuse);
-
+ canuse = matmod(u, rtype, canuse);
+ assert(canuse >= 0);
assert(canuse % 100 == 0
|| !"only constant multipliers are implemented in build()");
multi = canuse / 100;
@@ -468,14 +470,9 @@ static int count_materials(unit *u, const construction *type, int n, int complet
const struct resource_type *rtype = type->materials[c].rtype;
int need, prebuilt;
int canuse = get_pooled(u, rtype, GET_DEFAULT, INT_MAX);
+ canuse = matmod(u, rtype, canuse);
- if (building_is_active(u->building) && inside_building(u)) {
- canuse = matmod(u->building->type->attribs, u, rtype, canuse);
- }
-
- if (canuse < 0)
- return canuse; /* pass errors to caller */
- canuse = matmod(type->attribs, u, rtype, canuse);
+ assert(canuse >= 0);
if (type->reqsize > 1) {
prebuilt =
required(completed, type->reqsize, type->materials[c].number);
@@ -503,50 +500,30 @@ static int count_materials(unit *u, const construction *type, int n, int complet
* of the first object have already been finished. return the
* actual size that could be built.
*/
-int build(unit * u, const construction * ctype, int completed, int want)
+int build(unit * u, const construction * ctype, int completed, int want, int skill_mod)
{
- const construction *type = ctype;
+ const construction *con = ctype;
int skills = INT_MAX; /* number of skill points remainig */
int basesk = 0;
int made = 0;
if (want <= 0)
return 0;
- if (type == NULL)
+ if (con == NULL)
return ENOMATERIALS;
- if (type->improvement == NULL && completed == type->maxsize)
+ if (con->improvement == NULL && completed == con->maxsize)
return ECOMPLETE;
- if (type->btype != NULL) {
- building *b;
- if (!u->building || u->building->type != type->btype) {
- return EBUILDINGREQ;
- }
- b = inside_building(u);
- if (!b || !building_is_active(b)) {
- return EBUILDINGREQ;
- }
- }
-
- if (type->skill != NOSKILL) {
+ if (con->skill != NOSKILL) {
int effsk;
int dm = get_effect(u, oldpotiontype[P_DOMORE]);
assert(u->number);
- basesk = effskill(u, type->skill, 0);
+ basesk = effskill(u, con->skill, 0);
if (basesk == 0)
return ENEEDSKILL;
- effsk = basesk;
- if (building_is_active(u->building) && inside_building(u)) {
- effsk = skillmod(u->building->type->attribs, u, u->region, type->skill,
- effsk, SMF_PRODUCTION);
- }
- effsk = skillmod(type->attribs, u, u->region, type->skill,
- effsk, SMF_PRODUCTION);
- if (effsk < 0)
- return effsk; /* pass errors to caller */
- if (effsk == 0)
- return ENEEDSKILL;
+ effsk = basesk + skill_mod;
+ assert(effsk >= 0);
skills = effsk * u->number;
@@ -569,13 +546,13 @@ int build(unit * u, const construction * ctype, int completed, int want)
* type->improvement==type means build another object of the same time
* while material lasts type->improvement==x means build x when type
* is finished */
- while (type && type->improvement &&
- type->improvement != type &&
- type->maxsize > 0 && type->maxsize <= completed) {
- completed -= type->maxsize;
- type = type->improvement;
+ while (con && con->improvement &&
+ con->improvement != con &&
+ con->maxsize > 0 && con->maxsize <= completed) {
+ completed -= con->maxsize;
+ con = con->improvement;
}
- if (type == NULL) {
+ if (con == NULL) {
if (made == 0)
return ECOMPLETE;
break; /* completed */
@@ -586,15 +563,15 @@ int build(unit * u, const construction * ctype, int completed, int want)
* (enno): Nein, das ist f�r Dinge, bei denen die n�chste Ausbaustufe
* die gleiche wie die vorherige ist. z.b. gegenst�nde.
*/
- if (type->maxsize > 0) {
- completed = completed % type->maxsize;
+ if (con->maxsize > 0) {
+ completed = completed % con->maxsize;
}
else {
completed = 0;
- assert(type->reqsize >= 1);
+ assert(con->reqsize >= 1);
}
- if (basesk < type->minskill) {
+ if (basesk < con->minskill) {
if (made == 0)
return ELOWSKILL;
else
@@ -602,15 +579,15 @@ int build(unit * u, const construction * ctype, int completed, int want)
}
/* n = maximum buildable size */
- if (type->minskill > 1) {
- n = skills / type->minskill;
+ if (con->minskill > 1) {
+ n = skills / con->minskill;
}
else {
n = skills;
}
/* Flinkfingerring wirkt nicht auf Mengenbegrenzte (magische)
* Talente */
- if (skill_limit(u->faction, type->skill) == INT_MAX) {
+ if (skill_limit(u->faction, con->skill) == INT_MAX) {
const resource_type *ring = get_resourcetype(R_RING_OF_NIMBLEFINGER);
item *itm = ring ? *i_find(&u->items, ring->itype) : 0;
int i = itm ? itm->number : 0;
@@ -622,26 +599,26 @@ int build(unit * u, const construction * ctype, int completed, int want)
if (want < n) n = want;
- if (type->maxsize > 0) {
- n = MIN(type->maxsize - completed, n);
- if (type->improvement == NULL) {
+ if (con->maxsize > 0) {
+ n = MIN(con->maxsize - completed, n);
+ if (con->improvement == NULL) {
want = n;
}
}
- n = count_materials(u, type, n, completed);
+ n = count_materials(u, con, n, completed);
if (n <= 0) {
if (made == 0)
return ENOMATERIALS;
else
break;
}
- err = use_materials(u, type, n, completed);
+ err = use_materials(u, con, n, completed);
if (err < 0) {
return err;
}
made += n;
- skills -= n * type->minskill;
+ skills -= n * con->minskill;
want -= n;
completed = completed + n;
}
@@ -799,7 +776,7 @@ build_building(unit * u, const building_type * btype, int id, int want, order *
}
}
}
- built = build(u, btype->construction, built, n);
+ built = build(u, btype->construction, built, n, 0);
switch (built) {
case ECOMPLETE:
@@ -884,7 +861,7 @@ static void build_ship(unit * u, ship * sh, int want)
const construction *construction = sh->type->construction;
int size = (sh->size * DAMAGE_SCALE - sh->damage) / DAMAGE_SCALE;
int n;
- int can = build(u, construction, size, want);
+ int can = build(u, construction, size, want, 0);
if ((n = construction->maxsize - sh->size) > 0 && can > 0) {
if (can >= n) {
diff --git a/src/kernel/build.h b/src/kernel/build.h
index 7780a6cd2..c201d900b 100644
--- a/src/kernel/build.h
+++ b/src/kernel/build.h
@@ -32,39 +32,35 @@ extern "C" {
* wichtig
*/
- struct xml_tag;
-
typedef struct requirement {
const struct resource_type *rtype;
int number;
} requirement;
+ typedef enum construct_t {
+ CONS_OTHER,
+ CONS_ITEM,
+ CONS_BUILDING
+ } construct_t;
+
typedef struct construction {
+ construct_t type;
skill_t skill; /* skill req'd per point of size */
int minskill; /* skill req'd per point of size */
int maxsize; /* maximum size of this type */
int reqsize; /* size of object using up 1 set of requirement. */
requirement *materials; /* material req'd to build one object */
- const struct building_type *btype;
- /* building type required to make this thing */
+ /* only used by CONS_BUILDING: */
+ char * name; /* building level name */
struct construction *improvement;
- /* next level, if upgradable. if more than one of these items
- * can be built (weapons, armour) per turn, must not be NULL,
- * but point to the same type again:
- * const_sword.improvement = &const_sword
- * last level of a building points to NULL, as do objects of
- * an unlimited size.
- */
- struct attrib *attribs;
- /* stores skill modifiers and other attributes */
-
+ /* next level, if upgradable. */
} construction;
void free_construction(struct construction *cons);
- extern int destroy_cmd(struct unit *u, struct order *ord);
- extern int leave_cmd(struct unit *u, struct order *ord);
+ int destroy_cmd(struct unit *u, struct order *ord);
+ int leave_cmd(struct unit *u, struct order *ord);
void build_road(struct unit *u, int size, direction_t d);
void create_ship(struct unit *u, const struct ship_type *newtype,
@@ -74,22 +70,20 @@ extern "C" {
struct building *getbuilding(const struct region *r);
struct ship *getship(const struct region *r);
- void reportevent(struct region *r, char *s);
-
void shash(struct ship *sh);
void sunhash(struct ship *sh);
- extern int roqf_factor(void);
+ int roqf_factor(void);
+
+ int build(struct unit *u, const construction * ctype, int completed, int want, int skill_mod);
+ int maxbuild(const struct unit *u, const construction * cons);
+ struct message *msg_materials_required(struct unit *u, struct order *ord,
+ const struct construction *ctype, int multi);
- int build(struct unit *u, const construction * ctype, int completed, int want);
- extern int maxbuild(const struct unit *u, const construction * cons);
- extern struct message *msg_materials_required(struct unit *u,
- struct order *ord, const struct construction *ctype, int multi);
/** error messages that build may return: */
#define ELOWSKILL -1
#define ENEEDSKILL -2
#define ECOMPLETE -3
#define ENOMATERIALS -4
-#define EBUILDINGREQ -5
#ifdef __cplusplus
}
diff --git a/src/kernel/build.test.c b/src/kernel/build.test.c
index 77efcfd73..8cd408b09 100644
--- a/src/kernel/build.test.c
+++ b/src/kernel/build.test.c
@@ -63,36 +63,14 @@ static void test_build_requires_materials(CuTest *tc) {
u = setup_build(&bf);
set_level(u, SK_ARMORER, 2);
- CuAssertIntEquals(tc, ENOMATERIALS, build(u, &bf.cons, 0, 1));
+ CuAssertIntEquals(tc, ENOMATERIALS, build(u, &bf.cons, 0, 1, 0));
itype = bf.cons.materials[0].rtype->itype;
i_change(&u->items, itype, 2);
- CuAssertIntEquals(tc, 1, build(u, &bf.cons, 0, 1));
+ CuAssertIntEquals(tc, 1, build(u, &bf.cons, 0, 1, 0));
CuAssertIntEquals(tc, 1, i_get(u->items, itype));
teardown_build(&bf);
}
-static void test_build_requires_building(CuTest *tc) {
- build_fixture bf = { 0 };
- unit *u;
- const struct resource_type *rtype;
- building_type *btype;
-
- u = setup_build(&bf);
- rtype = bf.cons.materials[0].rtype;
- i_change(&u->items, rtype->itype, 1);
- set_level(u, SK_ARMORER, 2);
- bf.cons.btype = btype = bt_get_or_create("hodor");
- btype->maxcapacity = 1;
- btype->capacity = 1;
- CuAssertIntEquals_Msg(tc, "must be inside a production building", EBUILDINGREQ, build(u, &bf.cons, 0, 1));
- u->building = test_create_building(u->region, btype);
- fset(u->building, BLD_MAINTAINED);
- CuAssertIntEquals(tc, 1, build(u, &bf.cons, 0, 1));
- btype->maxcapacity = 0;
- CuAssertIntEquals_Msg(tc, "cannot build when production building capacity exceeded", EBUILDINGREQ, build(u, &bf.cons, 0, 1));
- teardown_build(&bf);
-}
-
static void test_build_failure_missing_skill(CuTest *tc) {
build_fixture bf = { 0 };
unit *u;
@@ -101,7 +79,7 @@ static void test_build_failure_missing_skill(CuTest *tc) {
u = setup_build(&bf);
rtype = bf.cons.materials[0].rtype;
i_change(&u->items, rtype->itype, 1);
- CuAssertIntEquals(tc, ENEEDSKILL, build(u, &bf.cons, 1, 1));
+ CuAssertIntEquals(tc, ENEEDSKILL, build(u, &bf.cons, 1, 1, 0));
teardown_build(&bf);
}
@@ -114,7 +92,7 @@ static void test_build_failure_low_skill(CuTest *tc) {
rtype = bf.cons.materials[0].rtype;
i_change(&u->items, rtype->itype, 1);
set_level(u, SK_ARMORER, bf.cons.minskill - 1);
- CuAssertIntEquals(tc, ELOWSKILL, build(u, &bf.cons, 0, 10));
+ CuAssertIntEquals(tc, ELOWSKILL, build(u, &bf.cons, 0, 10, 0));
teardown_build(&bf);
}
@@ -128,7 +106,7 @@ static void test_build_failure_completed(CuTest *tc) {
i_change(&u->items, rtype->itype, 1);
set_level(u, SK_ARMORER, bf.cons.minskill);
bf.cons.maxsize = 1;
- CuAssertIntEquals(tc, ECOMPLETE, build(u, &bf.cons, bf.cons.maxsize, 10));
+ CuAssertIntEquals(tc, ECOMPLETE, build(u, &bf.cons, bf.cons.maxsize, 10, 0));
CuAssertIntEquals(tc, 1, i_get(u->items, rtype->itype));
teardown_build(&bf);
}
@@ -143,19 +121,19 @@ static void test_build_limits(CuTest *tc) {
assert(rtype);
i_change(&u->items, rtype->itype, 1);
set_level(u, SK_ARMORER, bf.cons.minskill);
- CuAssertIntEquals(tc, 1, build(u, &bf.cons, 0, 10));
+ CuAssertIntEquals(tc, 1, build(u, &bf.cons, 0, 10, 0));
CuAssertIntEquals(tc, 0, i_get(u->items, rtype->itype));
scale_number(u, 2);
set_level(u, SK_ARMORER, bf.cons.minskill);
i_change(&u->items, rtype->itype, 2);
- CuAssertIntEquals(tc, 2, build(u, &bf.cons, 0, 10));
+ CuAssertIntEquals(tc, 2, build(u, &bf.cons, 0, 10, 0));
CuAssertIntEquals(tc, 0, i_get(u->items, rtype->itype));
scale_number(u, 2);
set_level(u, SK_ARMORER, bf.cons.minskill * 2);
i_change(&u->items, rtype->itype, 4);
- CuAssertIntEquals(tc, 4, build(u, &bf.cons, 0, 10));
+ CuAssertIntEquals(tc, 4, build(u, &bf.cons, 0, 10, 0));
CuAssertIntEquals(tc, 0, i_get(u->items, rtype->itype));
teardown_build(&bf);
}
@@ -174,7 +152,7 @@ static void test_build_with_ring(CuTest *tc) {
set_level(u, SK_ARMORER, bf.cons.minskill);
i_change(&u->items, rtype->itype, 20);
i_change(&u->items, ring, 1);
- CuAssertIntEquals(tc, 10, build(u, &bf.cons, 0, 20));
+ CuAssertIntEquals(tc, 10, build(u, &bf.cons, 0, 20, 0));
CuAssertIntEquals(tc, 10, i_get(u->items, rtype->itype));
teardown_build(&bf);
}
@@ -193,16 +171,16 @@ static void test_build_with_potion(CuTest *tc) {
i_change(&u->items, rtype->itype, 20);
change_effect(u, ptype, 4);
set_level(u, SK_ARMORER, bf.cons.minskill);
- CuAssertIntEquals(tc, 2, build(u, &bf.cons, 0, 20));
+ CuAssertIntEquals(tc, 2, build(u, &bf.cons, 0, 20, 0));
CuAssertIntEquals(tc, 18, i_get(u->items, rtype->itype));
CuAssertIntEquals(tc, 3, get_effect(u, ptype));
set_level(u, SK_ARMORER, bf.cons.minskill * 2);
- CuAssertIntEquals(tc, 4, build(u, &bf.cons, 0, 20));
+ CuAssertIntEquals(tc, 4, build(u, &bf.cons, 0, 20, 0));
CuAssertIntEquals(tc, 2, get_effect(u, ptype));
set_level(u, SK_ARMORER, bf.cons.minskill);
scale_number(u, 2); /* OBS: this scales the effects, too: */
CuAssertIntEquals(tc, 4, get_effect(u, ptype));
- CuAssertIntEquals(tc, 4, build(u, &bf.cons, 0, 20));
+ CuAssertIntEquals(tc, 4, build(u, &bf.cons, 0, 20, 0));
CuAssertIntEquals(tc, 2, get_effect(u, ptype));
teardown_build(&bf);
}
@@ -410,7 +388,6 @@ CuSuite *get_build_suite(void)
SUITE_ADD_TEST(suite, test_build_failure_low_skill);
SUITE_ADD_TEST(suite, test_build_failure_missing_skill);
SUITE_ADD_TEST(suite, test_build_requires_materials);
- SUITE_ADD_TEST(suite, test_build_requires_building);
SUITE_ADD_TEST(suite, test_build_failure_completed);
SUITE_ADD_TEST(suite, test_build_with_ring);
SUITE_ADD_TEST(suite, test_build_with_potion);
diff --git a/src/kernel/building.c b/src/kernel/building.c
index 6152622e8..bcc914cca 100644
--- a/src/kernel/building.c
+++ b/src/kernel/building.c
@@ -41,11 +41,12 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include
#include
#include
-#include
#include
#include
#include
+#include
+#include
/* libc includes */
#include
@@ -55,7 +56,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
/* attributes includes */
#include
-#include
typedef struct building_typelist {
struct building_typelist *next;
@@ -63,26 +63,28 @@ typedef struct building_typelist {
} building_typelist;
selist *buildingtypes = NULL;
+static critbit_tree cb_bldgtypes;
/* Returns a building type for the (internal) name */
static building_type *bt_find_i(const char *name)
{
- selist *ql;
- int qi;
+ const char *match;
+ building_type *btype = NULL;
- assert(name);
-
- for (qi = 0, ql = buildingtypes; ql; selist_advance(&ql, &qi, 1)) {
- building_type *btype = (building_type *)selist_get(ql, qi);
- if (strcmp(btype->_name, name) == 0)
- return btype;
+ match = cb_find_str(&cb_bldgtypes, name);
+ if (match) {
+ cb_get_kv(match, &btype, sizeof(btype));
}
- return NULL;
+ return btype;
}
const building_type *bt_find(const char *name)
{
- return bt_find_i(name);
+ building_type *btype = bt_find_i(name);
+ if (!btype) {
+ log_warning("bt_find: could not find building '%s'\n", name);
+ }
+ return btype;
}
static int bt_changes = 1;
@@ -97,12 +99,15 @@ bool bt_changed(int *cache)
return false;
}
-void bt_register(building_type * type)
+static void bt_register(building_type * btype)
{
- if (type->init) {
- type->init(type);
- }
- selist_push(&buildingtypes, (void *)type);
+ size_t len;
+ char data[64];
+
+ selist_push(&buildingtypes, (void *)btype);
+ len = cb_new_kv(btype->_name, strlen(btype->_name), &btype, sizeof(btype), data);
+ assert(len <= sizeof(data));
+ cb_insert(&cb_bldgtypes, data, len);
++bt_changes;
}
@@ -115,6 +120,7 @@ static void free_buildingtype(void *ptr) {
}
void free_buildingtypes(void) {
+ cb_clear(&cb_bldgtypes);
selist_foreach(buildingtypes, free_buildingtype);
selist_free(buildingtypes);
buildingtypes = 0;
@@ -123,6 +129,7 @@ void free_buildingtypes(void) {
building_type *bt_get_or_create(const char *name)
{
+ assert(name && name[0]);
if (name != NULL) {
building_type *btype = bt_find_i(name);
if (btype == NULL) {
@@ -160,27 +167,48 @@ attrib_type at_building_generic_type = {
ATF_UNIQUE
};
+/* TECH DEBT: simplest thing that works for E3 dwarf/halfling faction rules */
+static int adjust_size(const building *b, int bsize) {
+ assert(b);
+ if (config_get_int("rules.dwarf_castles", 0)
+ && strcmp(b->type->_name, "castle") == 0) {
+ unit *u = building_owner(b);
+ if (u && u->faction->race == get_race(RC_HALFLING)) {
+ return bsize * 5 / 4;
+ }
+ }
+ return bsize;
+}
+
/* Returns the (internal) name for a building of given size and type. Especially, returns the correct
* name if it depends on the size (as for Eressea castles).
*/
const char *buildingtype(const building_type * btype, const building * b, int bsize)
{
- const char *s;
+ const construction *con;
+
assert(btype);
- s = btype->_name;
- if (btype->name) {
- s = btype->name(btype, b, bsize);
- }
if (b && b->attribs) {
if (is_building_type(btype, "generic")) {
const attrib *a = a_find(b->attribs, &at_building_generic_type);
if (a) {
- s = (const char *)a->data.v;
+ return (const char *)a->data.v;
}
}
}
- return s;
+ if (btype->construction && btype->construction->name) {
+ if (b) {
+ bsize = adjust_size(b, bsize);
+ }
+ for (con = btype->construction; con; con = con->improvement) {
+ bsize -= con->maxsize;
+ if (!con->improvement || bsize <0) {
+ return con->name;
+ }
+ }
+ }
+ return btype->_name;
}
#define BMAXHASH 7919
@@ -222,80 +250,6 @@ building *findbuilding(int i)
{
return bfindhash(i);
}
-
-/* ** old building types ** */
-
-static int sm_smithy(const unit * u, const region * r, skill_t sk, int value)
-{ /* skillmod */
- if (sk == SK_WEAPONSMITH || sk == SK_ARMORER) {
- if (u->region == r)
- return value + 1;
- }
- return value;
-}
-
-static int mm_smithy(const unit * u, const resource_type * rtype, int value)
-{ /* material-mod */
- if (rtype == get_resourcetype(R_IRON))
- return value * 2;
- return value;
-}
-
-static void init_smithy(struct building_type *bt)
-{
- a_add(&bt->attribs, make_skillmod(NOSKILL, SMF_PRODUCTION, sm_smithy, 1.0,
- 0));
- a_add(&bt->attribs, make_matmod(mm_smithy));
-}
-
-static const char *castle_name_i(const struct building_type *btype,
- const struct building *b, int bsize, const char *fname[])
-{
- int i = bt_effsize(btype, b, bsize);
-
- return fname[i];
-}
-
-static const char *castle_name_2(const struct building_type *btype,
- const struct building *b, int bsize)
-{
- const char *fname[] = {
- "site",
- "fortification",
- "tower",
- "castle",
- "fortress",
- "citadel"
- };
- return castle_name_i(btype, b, bsize, fname);
-}
-
-static const char *castle_name(const struct building_type *btype,
- const struct building *b, int bsize)
-{
- const char *fname[] = {
- "site",
- "tradepost",
- "fortification",
- "tower",
- "castle",
- "fortress",
- "citadel"
- };
- return castle_name_i(btype, b, bsize, fname);
-}
-
-static const char *fort_name(const struct building_type *btype,
- const struct building *b, int bsize)
-{
- const char *fname[] = {
- "scaffolding",
- "guardhouse",
- "guardtower",
- };
- return castle_name_i(btype, b, bsize, fname);
-}
-
/* for finding out what was meant by a particular building string */
static local_names *bnames;
@@ -511,24 +465,19 @@ int buildingeffsize(const building * b, int img)
int bt_effsize(const building_type * btype, const building * b, int bsize)
{
- int i = bsize, n = 0;
+ int n = 0;
const construction *cons = btype->construction;
- /* TECH DEBT: simplest thing that works for E3 dwarf/halfling faction rules */
- if (b && config_get_int("rules.dwarf_castles", 0)
- && strcmp(btype->_name, "castle") == 0) {
- unit *u = building_owner(b);
- if (u && u->faction->race == get_race(RC_HALFLING)) {
- i = bsize * 10 / 8;
- }
+ if (b) {
+ bsize = adjust_size(b, bsize);
}
- if (!cons || !cons->improvement) {
+ if (!cons) {
return 0;
}
- while (cons && cons->maxsize != -1 && i >= cons->maxsize) {
- i -= cons->maxsize;
+ while (cons && cons->maxsize != -1 && bsize >= cons->maxsize) {
+ bsize -= cons->maxsize;
cons = cons->improvement;
++n;
}
@@ -577,10 +526,10 @@ static unit *building_owner_ex(const building * bld, const struct faction * last
}
if (!heir && config_token("rules.region_owner_pay_building", bld->type->_name)) {
if (rule_region_owners()) {
- u = building_owner(largestbuilding(bld->region, &cmp_taxes, false));
+ u = building_owner(largestbuilding(bld->region, cmp_taxes, false));
}
else {
- u = building_owner(largestbuilding(bld->region, &cmp_wage, false));
+ u = building_owner(largestbuilding(bld->region, cmp_wage, false));
}
if (u) {
heir = u;
@@ -699,7 +648,7 @@ building *largestbuilding(const region * r, cmp_building_cb cmp_gt,
{
building *b, *best = NULL;
- for (b = rbuildings(r); b; b = b->next) {
+ for (b = r->buildings; b; b = b->next) {
if (cmp_gt(b, best) <= 0)
continue;
if (!imaginary) {
@@ -727,7 +676,7 @@ static const int wagetable[7][4] = {
static int
default_wage(const region * r, const faction * f, const race * rc, int in_turn)
{
- building *b = largestbuilding(r, &cmp_wage, false);
+ building *b = largestbuilding(r, cmp_wage, false);
int esize = 0;
double wage;
static int ct_cache;
@@ -758,19 +707,12 @@ default_wage(const region * r, const faction * f, const race * rc, int in_turn)
else {
wage = wagetable[esize][2];
}
- if (rule_blessed_harvest() == HARVEST_WORK) {
+ if (r->attribs && rule_blessed_harvest() == HARVEST_WORK) {
/* E1 rules */
wage += curse_geteffect(get_curse(r->attribs, ct_find("blessedharvest")));
}
}
- /* Artsculpture: Income +5 */
- for (b = r->buildings; b; b = b->next) {
- if (is_building_type(b->type, "artsculpture")) {
- wage += 5;
- }
- }
-
if (r->attribs) {
attrib *a;
const struct curse_type *ctype;
@@ -808,10 +750,18 @@ minimum_wage(const region * r, const faction * f, const race * rc, int in_turn)
* die Bauern wenn f == NULL. */
int wage(const region * r, const faction * f, const race * rc, int in_turn)
{
- if (global.functions.wage) {
- return global.functions.wage(r, f, rc, in_turn);
+ static int config;
+ static int rule_wage;
+ if (config_changed(&config)) {
+ rule_wage = config_get_int("rules.wage.function", 1);
}
- return default_wage(r, f, rc, in_turn);
+ if (rule_wage==0) {
+ return 0;
+ }
+ if (rule_wage==1) {
+ return default_wage(r, f, rc, in_turn);
+ }
+ return minimum_wage(r, f, rc, in_turn);
}
int cmp_wage(const struct building *b, const building * a)
@@ -837,6 +787,12 @@ bool is_owner_building(const struct building * b)
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);
@@ -846,14 +802,12 @@ int cmp_taxes(const building * b, const building * a)
return -1;
}
else if (a) {
- int newsize = buildingeffsize(b, false);
- double newtaxes = b->type->taxes(b, newsize);
- int oldsize = buildingeffsize(a, false);
- double oldtaxes = a->type->taxes(a, oldsize);
+ int newtaxes = building_taxes(b);
+ int oldtaxes = building_taxes(a);
- if (newtaxes < oldtaxes)
+ if (newtaxes > oldtaxes)
return -1;
- else if (newtaxes > oldtaxes)
+ else if (newtaxes < oldtaxes)
return 1;
else if (b->size < a->size)
return -1;
@@ -862,8 +816,9 @@ int cmp_taxes(const building * b, const building * a)
else {
if (u && u->faction == f) {
u = building_owner(a);
- if (u && u->faction == f)
- return -1;
+ if (u && u->faction == f) {
+ return 0;
+ }
return 1;
}
}
@@ -872,7 +827,7 @@ int cmp_taxes(const building * b, const building * a)
return 1;
}
}
- return -1;
+ return 0;
}
int cmp_current_owner(const building * b, const building * a)
@@ -885,10 +840,8 @@ int cmp_current_owner(const building * b, const building * a)
if (!u || u->faction != f)
return -1;
if (a) {
- int newsize = buildingeffsize(b, false);
- double newtaxes = b->type->taxes(b, newsize);
- int oldsize = buildingeffsize(a, false);
- double oldtaxes = a->type->taxes(a, oldsize);
+ int newtaxes = building_taxes(b);
+ int oldtaxes = building_taxes(a);
if (newtaxes > oldtaxes) {
return 1;
@@ -896,23 +849,11 @@ int cmp_current_owner(const building * b, const building * a)
if (newtaxes < oldtaxes) {
return -1;
}
- if (newsize != oldsize) {
- return newsize - oldsize;
- }
return (b->size - a->size);
}
else {
return 1;
}
}
- return -1;
-}
-
-void register_buildings(void)
-{
- register_function((pf_generic)minimum_wage, "minimum_wage");
- register_function((pf_generic)init_smithy, "init_smithy");
- register_function((pf_generic)castle_name, "castle_name");
- register_function((pf_generic)castle_name_2, "castle_name_2");
- register_function((pf_generic)fort_name, "fort_name");
+ return 0;
}
diff --git a/src/kernel/building.h b/src/kernel/building.h
index 9cb675fc1..04ad08262 100644
--- a/src/kernel/building.h
+++ b/src/kernel/building.h
@@ -63,16 +63,11 @@ extern "C" {
variant magres; /* how well it resists against spells */
int magresbonus; /* bonus it gives the target against spells */
int fumblebonus; /* bonus that reduces fumbling */
+ int taxes; /* receive $1 tax per `taxes` in region */
double auraregen; /* modifier for aura regeneration inside building */
struct maintenance *maintenance; /* array of requirements */
struct construction *construction; /* construction of 1 building-level */
-
- const char *(*name) (const struct building_type *,
- const struct building * b, int size);
- void(*init) (struct building_type *);
- void(*age) (struct building *);
- double(*taxes) (const struct building *, int size);
- struct attrib *attribs;
+ struct resource_mod *modifiers; /* modify production skills */
} building_type;
extern struct selist *buildingtypes;
@@ -85,8 +80,6 @@ extern "C" {
bool bt_changed(int *cache);
const building_type *bt_find(const char *name);
void free_buildingtypes(void);
- void register_buildings(void);
- void bt_register(struct building_type *type);
int bt_effsize(const struct building_type *btype,
const struct building *b, int bsize);
@@ -141,6 +134,7 @@ extern "C" {
int cmp_taxes(const struct building *b, const struct building *bother);
int cmp_current_owner(const struct building *b,
const struct building *bother);
+ int building_taxes(const building *b);
/* old functions, still in build.c: */
int buildingeffsize(const building * b, int imaginary);
diff --git a/src/kernel/building.test.c b/src/kernel/building.test.c
index 3f415a913..588ec2937 100644
--- a/src/kernel/building.test.c
+++ b/src/kernel/building.test.c
@@ -21,14 +21,13 @@ static void test_register_building(CuTest * tc)
test_cleanup();
- btype = (building_type *)calloc(sizeof(building_type), 1);
- btype->_name = strdup("herp");
CuAssertIntEquals(tc, true, bt_changed(&cache));
CuAssertIntEquals(tc, false, bt_changed(&cache));
- bt_register(btype);
- CuAssertIntEquals(tc, true, bt_changed(&cache));
- CuAssertPtrNotNull(tc, bt_find("herp"));
+ btype = bt_get_or_create("herp");
+ CuAssertIntEquals(tc, true, bt_changed(&cache));
+ CuAssertPtrEquals(tc, btype, (void *)bt_find("herp"));
+
free_buildingtypes();
CuAssertIntEquals(tc, true, bt_changed(&cache));
test_cleanup();
@@ -295,11 +294,8 @@ static void test_btype_defaults(CuTest *tc) {
CuAssertStrEquals(tc, "hodor", btype->_name);
CuAssertPtrEquals(tc, 0, btype->maintenance);
CuAssertPtrEquals(tc, 0, btype->construction);
- CuAssertTrue(tc, !btype->name);
- CuAssertTrue(tc, !btype->init);
- CuAssertTrue(tc, !btype->age);
- CuAssertTrue(tc, !btype->taxes);
CuAssertDblEquals(tc, 1.0, btype->auraregen, 0.0);
+ CuAssertIntEquals(tc, 0, btype->taxes);
CuAssertIntEquals(tc, -1, btype->maxsize);
CuAssertIntEquals(tc, 1, btype->capacity);
CuAssertIntEquals(tc, -1, btype->maxcapacity);
@@ -428,10 +424,87 @@ static void test_cmp_castle_size(CuTest *tc) {
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, NULL)>0);
- CuAssertTrue(tc, cmp_castle_size(NULL, b1)<0);
+ 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();
+}
+
+static void test_cmp_wage(CuTest *tc) {
+ region *r;
+ building *b1, *b2;
+ building_type *btype;
+
+ test_setup();
+ btype = test_create_buildingtype("castle");
+ btype->taxes = 100;
+ r = test_create_region(0, 0, 0);
+ b1 = test_create_building(r, btype);
+ b2 = test_create_building(r, btype);
+ b1->size = 5;
+ b2->size = 10;
+ CuAssertPtrEquals(tc, b2, largestbuilding(r, cmp_wage, false));
+ CuAssertTrue(tc, cmp_wage(b1, b2) < 0);
+ CuAssertTrue(tc, cmp_wage(b2, b1) > 0);
+ CuAssertTrue(tc, cmp_wage(b1, b1) == 0);
+ test_cleanup();
+}
+
+static void test_cmp_taxes(CuTest *tc) {
+ region *r;
+ building *b1, *b2;
+ building_type *btype;
+ unit *u1, *u2;
+
+ test_setup();
+ btype = test_create_buildingtype("castle");
+ btype->taxes = 100;
+ r = test_create_region(0, 0, 0);
+ 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);
+ u_set_building(u1, b1);
+ u2 = test_create_unit(test_create_faction(0), 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();
+}
+
+static void test_cmp_current_owner(CuTest *tc) {
+ region *r;
+ building *b1, *b2;
+ building_type *btype;
+ unit *u1, *u2;
+
+ test_setup();
+ config_set("rules.region_owners", "1");
+ r = test_create_region(0, 0, 0);
+ btype = test_create_buildingtype("watch");
+ btype->construction->maxsize = 1;
+ btype->taxes = 200;
+ b1 = test_create_building(r, btype);
+ btype = test_create_buildingtype("castle");
+ btype->construction->maxsize = 1;
+ btype->taxes = 100;
+ b2 = test_create_building(r, btype);
+ b1->size = 1;
+ CuAssertIntEquals(tc, 1, buildingeffsize(b1, false));
+ b2->size = 1;
+ CuAssertIntEquals(tc, 1, buildingeffsize(b2, false));
+ u1 = test_create_unit(test_create_faction(0), r);
+ u_set_building(u1, b1);
+ u2 = test_create_unit(test_create_faction(0), 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();
}
@@ -460,10 +533,52 @@ static void test_building_effsize(CuTest *tc) {
test_cleanup();
}
+static int cmp_size(const building *lhs, const building *rhs) {
+ assert(lhs);
+ return rhs ? lhs->size - rhs->size : 1;
+}
+
+static void test_largestbuilding(CuTest *tc) {
+ region *r;
+ building *b1, *b2;
+ test_setup();
+ r = test_create_region(0, 0, NULL);
+ CuAssertPtrEquals(tc, NULL, largestbuilding(r, cmp_size, false));
+ b1 = test_create_building(r, NULL);
+ b2 = test_create_building(r, NULL);
+ b1->size = 1;
+ b2->size = 1;
+ CuAssertPtrEquals(tc, b1, largestbuilding(r, cmp_size, false));
+ b1->size = 2;
+ CuAssertPtrEquals(tc, b1, largestbuilding(r, cmp_size, false));
+ b2->size = 3;
+ CuAssertPtrEquals(tc, b2, largestbuilding(r, cmp_size, false));
+ test_cleanup();
+}
+
+static void test_buildingtype(CuTest *tc) {
+ building_type *btype;
+ test_setup();
+ btype = test_create_buildingtype("hodor");
+ CuAssertPtrNotNull(tc, btype->construction);
+ CuAssertStrEquals(tc, "hodor", buildingtype(btype, NULL, 1));
+ btype->construction->name = 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();
+}
+
CuSuite *get_building_suite(void)
{
CuSuite *suite = CuSuiteNew();
+ SUITE_ADD_TEST(suite, test_buildingtype);
+ SUITE_ADD_TEST(suite, test_largestbuilding);
SUITE_ADD_TEST(suite, test_cmp_castle_size);
+ SUITE_ADD_TEST(suite, test_cmp_taxes);
+ SUITE_ADD_TEST(suite, test_cmp_wage);
+ SUITE_ADD_TEST(suite, test_cmp_current_owner);
SUITE_ADD_TEST(suite, test_register_building);
SUITE_ADD_TEST(suite, test_btype_defaults);
SUITE_ADD_TEST(suite, test_building_set_owner);
diff --git a/src/kernel/callbacks.c b/src/kernel/callbacks.c
new file mode 100644
index 000000000..c1d52352a
--- /dev/null
+++ b/src/kernel/callbacks.c
@@ -0,0 +1,5 @@
+#include
+#include "callbacks.h"
+
+struct callback_struct callbacks = { 0 };
+
diff --git a/src/attributes/matmod.h b/src/kernel/callbacks.h
similarity index 61%
rename from src/attributes/matmod.h
rename to src/kernel/callbacks.h
index 99171d338..dcdf6ac90 100644
--- a/src/attributes/matmod.h
+++ b/src/kernel/callbacks.h
@@ -16,22 +16,31 @@ 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_MATMOD
-#define H_ATTRIBUTE_MATMOD
+#ifndef H_KRNL_CALLBACKS_H
+#define H_KRNL_CALLBACKS_H
#ifdef __cplusplus
extern "C" {
#endif
- struct resource_type;
+ struct castorder;
+ struct order;
struct unit;
- typedef int(*mm_fun) (const struct unit * u,
- const struct resource_type * rtype, int value);
+ struct region;
+ struct item_type;
+ struct resource_type;
- extern struct attrib_type at_matmod;
- extern struct attrib *make_matmod(mm_fun function);
+ struct callback_struct {
+ int (*cast_spell)(struct castorder *co, const char *fname);
+ int (*use_item)(struct unit *u, const struct item_type *itype,
+ int amount, struct order *ord);
+ void(*produce_resource)(struct region *, const struct resource_type *, int);
+ int(*limit_resource)(const struct region *, const struct resource_type *);
+ };
+ extern struct callback_struct callbacks;
#ifdef __cplusplus
}
#endif
-#endif
+#endif /* H_KRNL_CALLBACKS_H */
+
diff --git a/src/kernel/config.c b/src/kernel/config.c
index bf61c8f02..37765914b 100644
--- a/src/kernel/config.c
+++ b/src/kernel/config.c
@@ -93,12 +93,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include
#include
-struct settings global = {
- "Eressea", /* gamename */
-};
+struct settings global;
bool lomem = false;
-int turn = -1;
+int turn = 0;
const char *parameters[MAXPARAMS] = {
"LOCALE",
@@ -367,13 +365,26 @@ void init_options_translation(const struct locale * lang) {
}
}
-void init_locale(struct locale *lang)
+void init_races(struct locale *lang)
{
- variant var;
- int i;
const struct race *rc;
void **tokens;
+ tokens = get_translations(lang, UT_RACES);
+ for (rc = races; rc; rc = rc->next) {
+ const char *name;
+ variant var;
+ var.v = (void *)rc;
+ name = locale_string(lang, rc_name_s(rc, NAME_PLURAL), false);
+ if (name) addtoken((struct tnode **)tokens, name, var);
+ name = locale_string(lang, rc_name_s(rc, NAME_SINGULAR), false);
+ if (name) addtoken((struct tnode **)tokens, name, var);
+ }
+}
+
+static void init_magic(struct locale *lang)
+{
+ void **tokens;
tokens = get_translations(lang, UT_MAGIC);
if (tokens) {
const char *str = config_get("rules.magic.playerschools");
@@ -385,7 +396,9 @@ void init_locale(struct locale *lang)
sstr = strdup(str);
tok = strtok(sstr, " ");
while (tok) {
+ variant var;
const char *name;
+ int i;
for (i = 0; i != MAXMAGIETYP; ++i) {
if (strcmp(tok, magic_school[i]) == 0) break;
}
@@ -402,21 +415,14 @@ void init_locale(struct locale *lang)
}
free(sstr);
}
-
+}
+void init_locale(struct locale *lang)
+{
+ init_magic(lang);
init_directions(lang);
init_keywords(lang);
init_skills(lang);
-
- tokens = get_translations(lang, UT_RACES);
- for (rc = races; rc; rc = rc->next) {
- const char *name;
- var.v = (void *)rc;
- name = locale_string(lang, rc_name_s(rc, NAME_PLURAL), false);
- if (name) addtoken((struct tnode **)tokens, name, var);
- name = locale_string(lang, rc_name_s(rc, NAME_SINGULAR), false);
- if (name) addtoken((struct tnode **)tokens, name, var);
- }
-
+ init_races(lang);
init_parameters(lang);
init_options_translation(lang);
@@ -733,7 +739,7 @@ bool config_changed(int *cache_key) {
}
#define MAXKEYS 16
-void config_set_from(const dictionary *d)
+void config_set_from(const dictionary *d, const char *valid_keys[])
{
int s, nsec = iniparser_getnsec(d);
for (s=0;s!=nsec;++s) {
@@ -742,6 +748,7 @@ void config_set_from(const dictionary *d)
int k, nkeys = iniparser_getsecnkeys(d, sec);
const char *keys[MAXKEYS];
size_t slen = strlen(sec);
+
assert(nkeys <= MAXKEYS);
assert(slenunits; u; u = u->nextF) {
const race *rc = u_race(u);
- int x = (flags&COUNT_UNITS) ? 1 : u->number;
+ int x = u->number;
if (f->race != rc) {
if (!playerrace(rc)) {
if (flags&COUNT_MONSTERS) {
@@ -732,16 +732,6 @@ int count_faction(const faction * f, int flags)
return n;
}
-int count_units(const faction * f)
-{
- return count_faction(f, COUNT_ALL | COUNT_UNITS);
-}
-
-int count_all(const faction * f)
-{
- return count_faction(f, COUNT_ALL);
-}
-
int count_migrants(const faction * f)
{
return count_faction(f, COUNT_MIGRANTS);
@@ -752,7 +742,7 @@ int count_maxmigrants(const faction * f)
int formula = rc_migrants_formula(f->race);
if (formula == MIGRANTS_LOG10) {
- int nsize = count_all(f);
+ int nsize = f->num_people;
if (nsize > 0) {
int x = (int)(log10(nsize / 50.0) * 20);
if (x < 0) x = 0;
@@ -762,22 +752,6 @@ int count_maxmigrants(const faction * f)
return 0;
}
-static void init_maxmagicians(struct attrib *a)
-{
- a->data.i = MAXMAGICIANS;
-}
-
-attrib_type at_maxmagicians = {
- "maxmagicians",
- init_maxmagicians,
- NULL,
- NULL,
- a_writeint,
- a_readint,
- NULL,
- ATF_UNIQUE
-};
-
int max_magicians(const faction * f)
{
static int rule, config, rc_cache;
@@ -785,15 +759,9 @@ int max_magicians(const faction * f)
int m;
if (config_changed(&config)) {
- rule = config_get_int("rules.maxskills.magic", MAXMAGICIANS);
+ rule = config_get_int("rules.maxskills.magic", 3);
}
m = rule;
- if (f->attribs) {
- attrib *a = a_find(f->attribs, &at_maxmagicians);
- if (a) {
- m = a->data.i;
- }
- }
if (rc_changed(&rc_cache)) {
rc_elf = get_race(RC_ELF);
}
diff --git a/src/kernel/faction.h b/src/kernel/faction.h
index 0a0ac39d6..e0cd893a1 100644
--- a/src/kernel/faction.h
+++ b/src/kernel/faction.h
@@ -35,8 +35,6 @@ extern "C" {
struct gamedata;
struct selist;
- extern struct attrib_type at_maxmagicians;
-
/* faction flags */
#define FFL_NEWID (1<<0) /* Die Partei hat bereits einmal ihre no gewechselt */
#define FFL_ISNEW (1<<1)
@@ -44,8 +42,8 @@ extern "C" {
#define FFL_QUIT (1<<3)
#define FFL_CURSED (1<<4) /* you're going to have a bad time */
#define FFL_DEFENDER (1<<10)
-#define FFL_SELECT (1<<18) /* ehemals f->dh, u->dh, r->dh, etc... */
#define FFL_NOAID (1<<21) /* Hilfsflag Kampf */
+#define FFL_SELECT (1<<22) /* ehemals f->dh, u->dh, r->dh, etc... */
#define FFL_MARK (1<<23) /* f�r markierende algorithmen, die das
* hinterher auch wieder l�schen m�ssen!
* (FFL_SELECT muss man vorher initialisieren,
@@ -77,13 +75,10 @@ extern "C" {
magic_t magiegebiet;
int newbies;
int num_people; /* Anzahl Personen ohne Monster */
- int num_total; /* Anzahl Personen mit Monstern */
+ int num_units;
int options;
- int no_units;
struct ally *allies; /* alliedgroup and others should check sf.faction.alive before using a faction from f.allies */
struct group *groups; /* alliedgroup and others should check sf.faction.alive before using a faction from f.groups */
- int nregions;
- int money;
score_t score;
struct alliance *alliance;
int alliance_joindate; /* the turn on which the faction joined its current alliance (or left the last one) */
@@ -166,14 +161,10 @@ extern "C" {
#define COUNT_MONSTERS 0x01
#define COUNT_MIGRANTS 0x02
#define COUNT_DEFAULT 0x04
-#define COUNT_ALL 0x07
-#define COUNT_UNITS 0x10
int count_faction(const struct faction * f, int flags);
int count_migrants(const struct faction * f);
int count_maxmigrants(const struct faction * f);
- int count_all(const struct faction * f);
- int count_units(const struct faction * f);
int max_magicians(const struct faction * f);
struct faction *getfaction(void);
diff --git a/src/kernel/item.c b/src/kernel/item.c
index 605511005..04274d633 100644
--- a/src/kernel/item.c
+++ b/src/kernel/item.c
@@ -34,23 +34,18 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include "terrain.h"
#include "unit.h"
-/* triggers includes */
-#include
-#include
-
/* util includes */
#include
#include
-#include
-#include
#include
#include
#include
#include
#include
-#include
#include
+#include
+#include
#include
/* libc includes */
@@ -568,48 +563,6 @@ item *i_new(const item_type * itype, int size)
return i;
}
-#include "region.h"
-
-static int
-give_horses(unit * s, unit * d, const item_type * itype, int n,
-struct order *ord)
-{
- if (d == NULL) {
- int use = use_pooled(s, item2resource(itype), GET_SLACK, n);
- region *r = s->region;
- if (use < n) {
- use +=
- use_pooled(s, item2resource(itype), GET_RESERVE | GET_POOLED_SLACK,
- n - use);
- }
- if (r->land) {
- rsethorses(r, rhorses(r) + use);
- }
- return 0;
- }
- return -1; /* use the mechanism */
-}
-
-static int
-give_money(unit * s, unit * d, const item_type * itype, int n,
-struct order *ord)
-{
- if (d == NULL) {
- int use = use_pooled(s, item2resource(itype), GET_SLACK, n);
- region *r = s->region;
- if (use < n) {
- use +=
- use_pooled(s, item2resource(itype), GET_RESERVE | GET_POOLED_SLACK,
- n - use);
- }
- if (r->land) {
- rsetmoney(r, rmoney(r) + use);
- }
- return 0;
- }
- return -1; /* use the mechanism */
-}
-
const potion_type *oldpotiontype[MAX_POTIONS + 1];
/*** alte items ***/
@@ -668,27 +621,6 @@ int set_item(unit * u, const item_type *itype, int value)
return value;
}
-static int
-use_birthdayamulet(unit * u, const struct item_type *itype, int amount,
-struct order *ord)
-{
- direction_t d;
- message *msg = msg_message("meow", "");
-
- UNUSED_ARG(ord);
- UNUSED_ARG(amount);
- UNUSED_ARG(itype);
-
- add_message(&u->region->msgs, msg);
- for (d = 0; d < MAXDIRECTIONS; d++) {
- region *tr = rconnect(u->region, d);
- if (tr)
- add_message(&tr->msgs, msg);
- }
- msg_release(msg);
- return 0;
-}
-
/* t_item::flags */
#define FL_ITEM_CURSED (1<<0)
#define FL_ITEM_NOTLOST (1<<1)
@@ -696,34 +628,6 @@ struct order *ord)
#define FL_ITEM_ANIMAL (1<<3) /* ist ein Tier */
#define FL_ITEM_MOUNT ((1<<4) | FL_ITEM_ANIMAL) /* ist ein Reittier */
-/* ------------------------------------------------------------- */
-/* Kann auch von Nichtmagier benutzt werden, modifiziert Taktik fuer diese
- * Runde um -1 - 4 Punkte. */
-static int
-use_tacticcrystal(unit * u, const struct item_type *itype, int amount,
-struct order *ord)
-{
- int i;
- for (i = 0; i != amount; ++i) {
- int duration = 1; /* wirkt nur eine Runde */
- curse *c;
- float effect;
- float power = 5; /* Widerstand gegen Antimagiesprueche, ist in diesem
- Fall egal, da der curse fuer den Kampf gelten soll,
- der vor den Antimagiezaubern passiert */
-
- effect = (float)(rng_int() % 6 - 1);
- c = create_curse(u, &u->attribs, ct_find("skillmod"), power,
- duration, effect, u->number);
- c->data.i = SK_TACTICS;
- UNUSED_ARG(ord);
- }
- use_pooled(u, itype->rtype, GET_DEFAULT, amount);
- ADDMSG(&u->faction->msgs, msg_message("use_tacticcrystal",
- "unit region", u, u->region));
- return 0;
-}
-
typedef struct t_item {
const char *name;
/* [0]: Einzahl fuer eigene; [1]: Mehrzahl fuer eigene;
@@ -759,17 +663,6 @@ mod_dwarves_only(const unit * u, const region * r, skill_t sk, int value)
return -118;
}
-static int heal(unit * user, int effect)
-{
- int req = unit_max_hp(user) * user->number - user->hp;
- if (req > 0) {
- req = MIN(req, effect);
- effect -= req;
- user->hp += req;
- }
- return effect;
-}
-
void
register_item_give(int(*foo) (struct unit *, struct unit *,
const struct item_type *, int, struct order *), const char *name)
@@ -784,173 +677,6 @@ struct order *), const char *name)
register_function((pf_generic)foo, name);
}
-void
-register_item_useonother(int(*foo) (struct unit *, int,
-const struct item_type *, int, struct order *), const char *name)
-{
- register_function((pf_generic)foo, name);
-}
-
-static int
-use_healingpotion(struct unit *user, const struct item_type *itype, int amount,
-struct order *ord)
-{
- int effect = amount * 400;
- unit *u = user->region->units;
- effect = heal(user, effect);
- while (effect > 0 && u != NULL) {
- if (u->faction == user->faction) {
- effect = heal(u, effect);
- }
- u = u->next;
- }
- use_pooled(user, itype->rtype, GET_SLACK | GET_RESERVE | GET_POOLED_SLACK,
- amount);
- usetpotionuse(user, itype->rtype->ptype);
-
- ADDMSG(&user->faction->msgs, msg_message("usepotion",
- "unit potion", user, itype->rtype));
- return 0;
-}
-
-static int
-use_warmthpotion(struct unit *u, const struct item_type *itype, int amount,
-struct order *ord)
-{
- if (u->faction->race == get_race(RC_INSECT)) {
- fset(u, UFL_WARMTH);
- }
- else {
- /* nur fuer insekten: */
- cmistake(u, ord, 163, MSG_EVENT);
- return ECUSTOM;
- }
- use_pooled(u, itype->rtype, GET_SLACK | GET_RESERVE | GET_POOLED_SLACK,
- amount);
- usetpotionuse(u, itype->rtype->ptype);
-
- ADDMSG(&u->faction->msgs, msg_message("usepotion",
- "unit potion", u, itype->rtype));
- return 0;
-}
-
-static int
-use_foolpotion(struct unit *u, int targetno, const struct item_type *itype,
-int amount, struct order *ord)
-{
- unit *target = findunit(targetno);
- if (target == NULL || u->region != target->region) {
- ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found",
- ""));
- return ECUSTOM;
- }
- if (effskill(u, SK_STEALTH, 0) <= effskill(target, SK_PERCEPTION, 0)) {
- cmistake(u, ord, 64, MSG_EVENT);
- return ECUSTOM;
- }
- ADDMSG(&u->faction->msgs, msg_message("givedumb",
- "unit recipient amount", u, target, amount));
-
- change_effect(target, itype->rtype->ptype, amount);
- use_pooled(u, itype->rtype, GET_DEFAULT, amount);
- return 0;
-}
-
-static int
-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);
- }
- else {
- const race *irace = u_irace(u);
- if (irace == u_race(u)) {
- const race *rcfailure = rc_find("smurf");
- if (!rcfailure) {
- rcfailure = rc_find("toad");
- }
- if (rcfailure) {
- trigger *trestore = trigger_changerace(u, u_race(u), irace);
- if (trestore) {
- int duration = 2 + rng_int() % 8;
-
- add_trigger(&u->attribs, "timer", trigger_timeout(duration,
- trestore));
- u->irace = NULL;
- u_setrace(u, rcfailure);
- }
- }
- }
- }
- use_pooled(u, itype->rtype, GET_SLACK | GET_RESERVE | GET_POOLED_SLACK,
- amount);
- usetpotionuse(u, itype->rtype->ptype);
-
- ADDMSG(&u->faction->msgs, msg_message("usepotion",
- "unit potion", u, itype->rtype));
- return 0;
-}
-
-#include
-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;
- }
- 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;
-}
-
-static int
-use_magicboost(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);
- faction *f = user->faction;
- if (user->number > mtoes) {
- ADDMSG(&user->faction->msgs, msg_message("use_singleperson",
- "unit item region command", user, itype->rtype, user->region, ord));
- return -1;
- }
- if (!is_mage(user) || key_get(f->attribs, atoi36("mbst"))) {
- cmistake(user, user->thisorder, 214, MSG_EVENT);
- return -1;
- }
- use_pooled(user, itype->rtype, GET_SLACK | GET_RESERVE | GET_POOLED_SLACK,
- user->number);
-
- key_set(&f->attribs, atoi36("mbst"), turn);
- set_level(user, SK_MAGIC, 3);
-
- ADDMSG(&user->faction->msgs, msg_message("use_item",
- "unit item", user, itype->rtype));
-
- return 0;
-}
-
-static int
-use_snowball(struct unit *user, const struct item_type *itype, int amount,
-struct order *ord)
-{
- return 0;
-}
-
static void init_oldpotions(void)
{
const char *potionnames[MAX_POTIONS] = {
@@ -982,7 +708,6 @@ void init_resources(void)
rtype->uchange = res_changeitem;
rtype->itype = it_get_or_create(rtype);
rtype->itype->weight = 1;
- rtype->itype->give = give_money;
rtype = rt_get_or_create(resourcenames[R_HORSE]);
rtype->flags |= RTF_ITEM | RTF_LIMITED;
@@ -1186,25 +911,27 @@ void read_items(struct storage *store, item ** ilist)
{
for (;;) {
char ibuf[32];
- const item_type *itype;
int i;
READ_STR(store, ibuf, sizeof(ibuf));
if (!strcmp("end", ibuf)) {
break;
}
- itype = it_find(ibuf);
READ_INT(store, &i);
- if (i <= 0) {
- log_error("data contains an entry with %d %s", i, ibuf);
- }
- else {
- if (itype && itype->rtype) {
- i_change(ilist, itype, i);
+ if (ilist) {
+ const item_type *itype;
+ itype = it_find(ibuf);
+ if (i <= 0) {
+ log_error("data contains an entry with %d %s", i, ibuf);
}
else {
- log_error("data contains unknown item type %s.", ibuf);
+ if (itype && itype->rtype) {
+ i_change(ilist, itype, i);
+ }
+ else {
+ log_error("data contains unknown item type %s.", ibuf);
+ }
+ assert(itype && itype->rtype);
}
- assert(itype && itype->rtype);
}
}
}
@@ -1242,15 +969,12 @@ void free_rtype(resource_type *rtype) {
if (rtype->wtype) {
free_wtype(rtype->wtype);
}
- if (rtype->atype) {
- free(rtype->atype);
- }
if (rtype->itype) {
free_itype(rtype->itype);
}
- if (rtype->raw) {
- free(rtype->raw);
- }
+ free(rtype->atype);
+ free(rtype->modifiers);
+ free(rtype->raw);
free(rtype->_name);
free(rtype);
}
@@ -1296,18 +1020,4 @@ void register_resources(void)
register_function((pf_generic)res_changepermaura, "changepermaura");
register_function((pf_generic)res_changehp, "changehp");
register_function((pf_generic)res_changeaura, "changeaura");
-
- register_item_use(use_potion, "usepotion");
- register_item_use(use_potion_delayed, "usepotion_delayed");
- register_item_use(use_tacticcrystal, "use_tacticcrystal");
- register_item_use(use_birthdayamulet, "use_birthdayamulet");
- register_item_use(use_warmthpotion, "usewarmthpotion");
- register_item_use(use_bloodpotion, "usebloodpotion");
- register_item_use(use_healingpotion, "usehealingpotion");
- register_item_useonother(use_foolpotion, "usefoolpotion");
- register_item_use(use_mistletoe, "usemistletoe");
- register_item_use(use_magicboost, "usemagicboost");
- register_item_use(use_snowball, "usesnowball");
-
- register_item_give(give_horses, "givehorses");
}
diff --git a/src/kernel/item.h b/src/kernel/item.h
index bb114c8ac..51ebcd2a1 100644
--- a/src/kernel/item.h
+++ b/src/kernel/item.h
@@ -39,7 +39,7 @@ extern "C" {
struct storage;
struct gamedata;
struct rawmaterial_type;
- struct resource_limit;
+ struct resource_mod;
typedef struct item {
struct item *next;
@@ -68,8 +68,6 @@ extern "C" {
typedef int(*rtype_uchange) (struct unit * user,
const struct resource_type * rtype, int delta);
- typedef int(*rtype_uget) (const struct unit * user,
- const struct resource_type * rtype);
typedef char *(*rtype_name) (const struct resource_type * rtype, int flags);
typedef struct resource_type {
/* --- constants --- */
@@ -77,12 +75,10 @@ extern "C" {
unsigned int flags;
/* --- functions --- */
rtype_uchange uchange;
- rtype_uget uget;
rtype_name name;
struct rawmaterial_type *raw;
- struct resource_limit *limit;
+ struct resource_mod *modifiers;
/* --- pointers --- */
- struct attrib *attribs;
struct item_type *itype;
struct potion_type *ptype;
struct luxury_type *ltype;
@@ -94,11 +90,6 @@ extern "C" {
const resource_type *findresourcetype(const char *name,
const struct locale *lang);
- /* resource-limits for regions */
-#define RMF_SKILL 0x01 /* int, bonus on resource production skill */
-#define RMF_SAVEMATERIAL 0x02 /* fraction (sa[0]/sa[1]), multiplier on resource usage */
-#define RMF_REQUIREDBUILDING 0x04 /* building, required to build */
-
/* bitfield values for item_type::flags */
#define ITF_NONE 0x0000
#define ITF_HERB 0x0001 /* this item is a herb */
@@ -107,6 +98,7 @@ extern "C" {
#define ITF_BIG 0x0008 /* big item, e.g. does not fit in a bag of holding */
#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 */
/* error codes for item_type::use */
#define ECUSTOM -1
@@ -120,17 +112,10 @@ extern "C" {
unsigned int flags;
int weight;
int capacity;
+ int mask_allow;
+ int mask_deny;
struct construction *construction;
char *_appearance[2]; /* wie es f�r andere aussieht */
- /* --- functions --- */
- bool(*canuse) (const struct unit * user,
- const struct item_type * itype);
- int(*use) (struct unit * user, const struct item_type * itype, int amount,
- struct order * ord);
- int(*useonother) (struct unit * user, int targetno,
- const struct item_type * itype, int amount, struct order * ord);
- int(*give) (struct unit * src, struct unit * dest,
- const struct item_type * itm, int number, struct order * ord);
int score;
} item_type;
@@ -321,8 +306,6 @@ extern "C" {
const struct item_type *, int, struct order *), const char *name);
void register_item_use(int(*foo) (struct unit *,
const struct item_type *, int, struct order *), const char *name);
- void register_item_useonother(int(*foo) (struct unit *, int,
- const struct item_type *, int, struct order *), const char *name);
void free_resources(void);
diff --git a/src/kernel/item.test.c b/src/kernel/item.test.c
index 6e3615797..c1c64bf62 100644
--- a/src/kernel/item.test.c
+++ b/src/kernel/item.test.c
@@ -162,7 +162,6 @@ static void test_core_resources(CuTest *tc) {
CuAssertPtrNotNull(tc, rtype = rt_find("money"));
CuAssertPtrNotNull(tc, rtype->itype);
CuAssertPtrNotNull(tc, rtype->uchange);
- CuAssertPtrNotNull(tc, rtype->itype->give);
CuAssertPtrNotNull(tc, rtype = rt_find("peasant"));
CuAssertPtrEquals(tc, 0, rtype->itype);
CuAssertPtrNotNull(tc, rtype = rt_find("permaura"));
diff --git a/src/kernel/jsonconf.c b/src/kernel/jsonconf.c
index 0f5642c42..609e73aac 100644
--- a/src/kernel/jsonconf.c
+++ b/src/kernel/jsonconf.c
@@ -33,6 +33,8 @@ without prior permission by the authors of Eressea.
/* game modules */
#include "prefix.h"
+#include "move.h"
+#include "calendar.h"
/* util includes */
#include
@@ -337,11 +339,6 @@ static void json_building(cJSON *json, building_type *bt) {
}
break;
case cJSON_String:
- if (strcmp(child->string, "name") == 0) {
- bt->name = (const char *(*)(const struct building_type *,
- const struct building *, int))get_function(child->valuestring);
- break;
- }
log_error("building %s contains unknown attribute %s", json->string, child->string);
break;
default:
@@ -588,18 +585,12 @@ static void json_spells(cJSON *json) {
for (child = json->child; child; child = child->next) {
if (child->type == cJSON_Object) {
spell *sp;
- cJSON * item = cJSON_GetObjectItem(child, "index");
- sp = create_spell(child->string, item ? item->valueint : 0);
+ cJSON * item;
+ sp = create_spell(child->string);
for (item = child->child; item; item = item->next) {
if (strcmp(item->string, "index") == 0) {
continue;
}
- else if (strcmp(item->string, "cast") == 0) {
- sp->cast = (spell_f)get_function(item->valuestring);
- }
- else if (strcmp(item->string, "fumble") == 0) {
- sp->fumble = (fumble_f)get_function(item->valuestring);
- }
else if (strcmp(item->string, "syntax") == 0) {
sp->syntax = strdup(item->valuestring);
}
@@ -690,6 +681,74 @@ static void json_direction(cJSON *json, struct locale *lang) {
}
}
+static void json_calendar(cJSON *json) {
+ cJSON *child;
+ if (json->type != cJSON_Object) {
+ log_error("calendar is not an object: %d", json->type);
+ return;
+ }
+ for (child = json->child; child; child = child->next) {
+ if (strcmp(child->string, "start") == 0) {
+ config_set_int("game.start", child->valueint);
+ }
+ else if (strcmp(child->string, "weeks") == 0) {
+ cJSON *entry;
+ int i;
+ if (child->type != cJSON_Array) {
+ log_error("calendar.weeks is not an array: %d", json->type);
+ return;
+ }
+ weeks_per_month = cJSON_GetArraySize(child);
+ free(weeknames);
+ 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);
+ }
+ else {
+ log_error("calendar.weeks[%d] is not a string: %d", i, json->type);
+ free(weeknames);
+ weeknames = NULL;
+ return;
+ }
+ }
+ assert(i == weeks_per_month);
+ free(weeknames2);
+ weeknames2 = malloc(sizeof(char *) * weeks_per_month);
+ for (i = 0; i != weeks_per_month; ++i) {
+ weeknames2[i] = malloc(strlen(weeknames[i]) + 3);
+ sprintf(weeknames2[i], "%s_d", weeknames[i]);
+ }
+ }
+ else if (strcmp(child->string, "months") == 0) {
+ cJSON *jmonth;
+ int i;
+ if (child->type != cJSON_Array) {
+ log_error("calendar.seasons is not an array: %d", json->type);
+ return;
+ }
+ free(month_season);
+ month_season = NULL;
+ free(storms);
+ months_per_year = cJSON_GetArraySize(child);
+ storms = malloc(sizeof(int) * months_per_year);
+ month_season = malloc(sizeof(int) * months_per_year);
+ for (i = 0, jmonth = child->child; jmonth; jmonth = jmonth->next, ++i) {
+ if (jmonth->type == cJSON_Object) {
+ storms[i] = cJSON_GetObjectItem(jmonth, "storm")->valueint;
+ month_season[i] = cJSON_GetObjectItem(jmonth, "season")->valueint;
+ }
+ else {
+ log_error("calendar.months[%d] is not an object: %d", i, json->type);
+ free(storms);
+ storms = NULL;
+ return;
+ }
+ }
+ }
+ }
+}
+
static void json_directions(cJSON *json) {
cJSON *child;
if (json->type != cJSON_Object) {
@@ -896,6 +955,9 @@ void json_config(cJSON *json) {
else if (strcmp(child->string, "strings") == 0) {
json_strings(child);
}
+ else if (strcmp(child->string, "calendar") == 0) {
+ json_calendar(child);
+ }
else if (strcmp(child->string, "directions") == 0) {
json_directions(child);
}
diff --git a/src/kernel/jsonconf.test.c b/src/kernel/jsonconf.test.c
index 456a27d22..2f54eeb8d 100644
--- a/src/kernel/jsonconf.test.c
+++ b/src/kernel/jsonconf.test.c
@@ -13,6 +13,8 @@
#include "order.h"
#include "terrain.h"
+#include "move.h"
+#include "calendar.h"
#include "prefix.h"
#include "util/language.h"
@@ -75,7 +77,7 @@ static void test_settings(CuTest * tc)
"\"float\" : 1.5 }}";
cJSON *json = cJSON_Parse(data);
- test_cleanup();
+ test_setup();
config_set("game.id", "42"); /* should not be replaced */
config_set("game.name", "Eressea"); /* should not be replaced */
json_config(json);
@@ -99,7 +101,7 @@ static void test_prefixes(CuTest * tc)
"]}";
cJSON *json = cJSON_Parse(data);
- test_cleanup();
+ test_setup();
json_config(json);
CuAssertPtrNotNull(tc, race_prefixes);
CuAssertStrEquals(tc, "snow", race_prefixes[0]);
@@ -119,7 +121,7 @@ static void test_disable(CuTest * tc)
"]}";
cJSON *json = cJSON_Parse(data);
- test_cleanup();
+ test_setup();
CuAssertTrue(tc, skill_enabled(SK_ALCHEMY));
CuAssertTrue(tc, !keyword_disabled(K_BANNER));
CuAssertTrue(tc, !keyword_disabled(K_PAY));
@@ -135,6 +137,31 @@ static void test_disable(CuTest * tc)
test_cleanup();
}
+static void test_calendar(CuTest * tc)
+{
+ const char * data = "{\"calendar\": { "
+ "\"weeks\" : [ \"one\", \"two\", \"three\" ],"
+ "\"months\" : ["
+ "{ \"storm\" : 99, \"season\" : 1 },"
+ "{ \"storm\" : 22, \"season\" : 2 }"
+ "]"
+ "}}";
+ cJSON *json = cJSON_Parse(data);
+
+ test_setup();
+ json_config(json);
+ CuAssertPtrNotNull(tc, storms);
+ CuAssertIntEquals(tc, 2, months_per_year);
+ CuAssertIntEquals(tc, 3, weeks_per_month);
+ CuAssertIntEquals(tc, 99, storms[0]);
+ CuAssertIntEquals(tc, 22, storms[1]);
+ CuAssertPtrNotNull(tc, month_season);
+ CuAssertIntEquals(tc, 1, month_season[0]);
+ CuAssertIntEquals(tc, 2, month_season[1]);
+ cJSON_Delete(json);
+ test_cleanup();
+}
+
static void test_races(CuTest * tc)
{
const char * data = "{\"races\": { \"orc\" : { "
@@ -155,7 +182,7 @@ static void test_races(CuTest * tc)
cJSON *json = cJSON_Parse(data);
const struct race *rc;
- test_cleanup();
+ test_setup();
CuAssertPtrNotNull(tc, json);
CuAssertPtrEquals(tc, 0, races);
@@ -189,7 +216,7 @@ static void test_findrace(CuTest *tc) {
const race *rc;
CuAssertPtrNotNull(tc, json);
- test_cleanup();
+ test_setup();
lang = get_or_create_locale("de");
CuAssertPtrEquals(tc, 0, (void *)findrace("Zwerg", lang));
@@ -211,7 +238,7 @@ static void test_items(CuTest * tc)
cJSON *json = cJSON_Parse(data);
const item_type * itype;
- test_cleanup();
+ test_setup();
CuAssertPtrNotNull(tc, json);
CuAssertPtrEquals(tc, 0, it_find("axe"));
@@ -249,7 +276,7 @@ static void test_ships(CuTest * tc)
const ship_type *st;
const terrain_type *ter;
- test_cleanup();
+ test_setup();
CuAssertPtrNotNull(tc, json);
CuAssertPtrEquals(tc, 0, shiptypes);
@@ -286,7 +313,7 @@ static void test_castles(CuTest *tc) {
cJSON *json = cJSON_Parse(data);
const building_type *bt;
- test_cleanup();
+ test_setup();
CuAssertPtrNotNull(tc, json);
CuAssertPtrEquals(tc, 0, buildingtypes);
@@ -311,7 +338,7 @@ static void test_spells(CuTest * tc)
cJSON *json = cJSON_Parse(data);
const spell *sp;
- test_cleanup();
+ test_setup();
CuAssertPtrNotNull(tc, json);
CuAssertPtrEquals(tc, 0, find_spell("fireball"));
@@ -350,7 +377,7 @@ static void test_buildings(CuTest * tc)
cJSON *json = cJSON_Parse(building_data);
const building_type *bt;
- test_cleanup();
+ test_setup();
CuAssertPtrNotNull(tc, json);
CuAssertPtrEquals(tc, 0, buildingtypes);
@@ -400,7 +427,7 @@ static void test_buildings_default(CuTest * tc)
const building_type *bt;
building_type clone;
- test_cleanup();
+ test_setup();
bt = bt_get_or_create("house");
clone = *bt;
@@ -425,7 +452,7 @@ static void test_ships_default(CuTest * tc)
const ship_type *st;
ship_type clone;
- test_cleanup();
+ test_setup();
st = st_get_or_create("hodor");
clone = *st;
@@ -446,7 +473,7 @@ static void test_configs(CuTest * tc)
FILE *F;
cJSON *json = cJSON_Parse(data);
- test_cleanup();
+ test_setup();
F = fopen("test.json", "w");
fwrite(building_data, 1, strlen(building_data), F);
@@ -475,7 +502,7 @@ static void test_terrains(CuTest * tc)
cJSON *json = cJSON_Parse(data);
- test_cleanup();
+ test_setup();
CuAssertPtrNotNull(tc, json);
CuAssertPtrEquals(tc, 0, (void *)get_terrain("plain"));
@@ -511,7 +538,7 @@ static void test_directions(CuTest * tc)
cJSON *json = cJSON_Parse(data);
- test_cleanup();
+ test_setup();
lang = get_or_create_locale("de");
CuAssertPtrNotNull(tc, json);
CuAssertIntEquals(tc, NODIRECTION, get_direction("ost", lang));
@@ -533,7 +560,7 @@ static void test_skills(CuTest * tc)
cJSON *json = cJSON_Parse(data);
- test_cleanup();
+ test_setup();
lang = get_or_create_locale("de");
CuAssertPtrNotNull(tc, json);
CuAssertIntEquals(tc, NOSKILL, get_skill("potato", lang));
@@ -558,7 +585,7 @@ static void test_keywords(CuTest * tc)
cJSON *json = cJSON_Parse(data);
- test_cleanup();
+ test_setup();
lang = get_or_create_locale("de");
CuAssertPtrNotNull(tc, json);
CuAssertIntEquals(tc, NOKEYWORD, get_keyword("potato", lang));
@@ -583,7 +610,7 @@ static void test_strings(CuTest * tc)
cJSON *json = cJSON_Parse(data);
CuAssertPtrNotNull(tc, json);
- test_cleanup();
+ test_setup();
lang = get_or_create_locale("de");
CuAssertPtrNotNull(tc, lang);
CuAssertPtrEquals(tc, NULL, (void *)LOC(lang, "move"));
@@ -640,6 +667,7 @@ CuSuite *get_jsonconf_suite(void)
SUITE_ADD_TEST(suite, test_prefixes);
SUITE_ADD_TEST(suite, test_disable);
SUITE_ADD_TEST(suite, test_infinitive_from_config);
+ SUITE_ADD_TEST(suite, test_calendar);
return suite;
}
diff --git a/src/kernel/messages.c b/src/kernel/messages.c
index f74e9c0d7..d3cd4f99b 100644
--- a/src/kernel/messages.c
+++ b/src/kernel/messages.c
@@ -78,16 +78,14 @@ variant v)
struct message *msg_feedback(const struct unit *u, struct order *ord,
const char *name, const char *sig, ...)
{
- va_list marker;
const message_type *mtype = mt_find(name);
- char paramname[64];
- const char *ic = sig;
variant args[16];
variant var;
memset(args, 0, sizeof(args));
- if (ord == NULL)
- ord = u->thisorder;
+ if (ord && ord->_noerror) {
+ return NULL;
+ }
if (!mtype) {
log_warning("trying to create message of unknown type \"%s\"\n", name);
@@ -106,41 +104,46 @@ struct message *msg_feedback(const struct unit *u, struct order *ord,
var.v = (void *)ord;
arg_set(args, mtype, "command", var);
- va_start(marker, sig);
- while (*ic && !isalnum(*ic))
- ic++;
- while (*ic) {
- char *oc = paramname;
- int i;
+ if (sig) {
+ const char *ic = sig;
+ va_list marker;
- while (isalnum(*ic))
- *oc++ = *ic++;
- *oc = '\0';
-
- for (i = 0; i != mtype->nparameters; ++i) {
- if (!strcmp(paramname, mtype->pnames[i]))
- break;
- }
- if (i != mtype->nparameters) {
- if (mtype->types[i]->vtype == VAR_VOIDPTR) {
- args[i].v = va_arg(marker, void *);
- }
- else if (mtype->types[i]->vtype == VAR_INT) {
- args[i].i = va_arg(marker, int);
- }
- else {
- assert(!"unknown variant type");
- }
- }
- else {
- log_error("invalid parameter %s for message type %s\n", paramname, mtype->name);
- assert(!"program aborted.");
- }
+ va_start(marker, sig);
while (*ic && !isalnum(*ic))
ic++;
- }
- va_end(marker);
+ while (*ic) {
+ char paramname[64];
+ char *oc = paramname;
+ int i;
+ while (isalnum(*ic))
+ *oc++ = *ic++;
+ *oc = '\0';
+
+ for (i = 0; i != mtype->nparameters; ++i) {
+ if (!strcmp(paramname, mtype->pnames[i]))
+ break;
+ }
+ if (i != mtype->nparameters) {
+ if (mtype->types[i]->vtype == VAR_VOIDPTR) {
+ args[i].v = va_arg(marker, void *);
+ }
+ else if (mtype->types[i]->vtype == VAR_INT) {
+ args[i].i = va_arg(marker, int);
+ }
+ else {
+ assert(!"unknown variant type");
+ }
+ }
+ else {
+ log_error("invalid parameter %s for message type %s\n", paramname, mtype->name);
+ assert(!"program aborted.");
+ }
+ while (*ic && !isalnum(*ic))
+ ic++;
+ }
+ va_end(marker);
+ }
return msg_create(mtype, args);
}
@@ -248,8 +251,9 @@ void addmessage(region * r, faction * f, const char *s, msg_t mtype, int level)
message * msg_error(const unit * u, struct order *ord, int mno) {
static char msgname[20];
- if (fval(u->faction, FFL_NPC))
- return 0;
+ if (fval(u->faction, FFL_NPC)) {
+ return NULL;
+ }
sprintf(msgname, "error%d", mno);
return msg_feedback(u, ord, msgname, "");
}
@@ -259,7 +263,9 @@ message * cmistake(const unit * u, struct order *ord, int mno, int mtype)
message * result;
UNUSED_ARG(mtype);
result = msg_error(u, ord, mno);
- ADDMSG(&u->faction->msgs, result);
+ if (result) {
+ ADDMSG(&u->faction->msgs, result);
+ }
return result;
}
@@ -267,7 +273,9 @@ void syntax_error(const struct unit *u, struct order *ord)
{
message * result;
result = msg_error(u, ord, 10);
- ADDMSG(&u->faction->msgs, result);
+ if (result) {
+ ADDMSG(&u->faction->msgs, result);
+ }
}
void free_messagelist(mlist *msgs)
diff --git a/src/kernel/messages.test.c b/src/kernel/messages.test.c
index 7b0f2dd5e..cd301756d 100644
--- a/src/kernel/messages.test.c
+++ b/src/kernel/messages.test.c
@@ -1,6 +1,9 @@
#include
#include "messages.h"
+#include "unit.h"
+#include "order.h"
+
#include
#include
@@ -68,11 +71,27 @@ static void test_merge_split(CuTest *tc) {
test_cleanup();
}
+static void test_noerror(CuTest *tc) {
+ unit *u;
+ struct locale *lang;
+
+ test_setup();
+ lang = test_create_locale();
+ u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL));
+ u->thisorder = parse_order("!@move", lang);
+ CuAssertTrue(tc, u->thisorder->_persistent);
+ CuAssertTrue(tc, u->thisorder->_noerror);
+ CuAssertPtrEquals(tc, NULL, msg_error(u, u->thisorder, 100));
+ CuAssertPtrEquals(tc, NULL, msg_feedback(u, u->thisorder, "error_unit_not_found", NULL));
+ test_cleanup();
+}
+
CuSuite *get_messages_suite(void) {
CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, test_missing_message);
SUITE_ADD_TEST(suite, test_merge_split);
SUITE_ADD_TEST(suite, test_message);
+ SUITE_ADD_TEST(suite, test_noerror);
return suite;
}
diff --git a/src/kernel/order.c b/src/kernel/order.c
index 776190b67..6fbb53040 100644
--- a/src/kernel/order.c
+++ b/src/kernel/order.c
@@ -44,13 +44,8 @@ static struct locale_data *locale_array[MAXLOCALES];
typedef struct order_data {
const char *_str;
-# ifdef LOMEM
- int _refcount:20;
- int _lindex:4;
-# else
int _refcount;
int _lindex;
-# endif
keyword_t _keyword;
} order_data;
@@ -99,6 +94,15 @@ char* get_command(const order *ord, char *sbuffer, size_t size) {
keyword_t kwd = ORD_KEYWORD(ord);
int bytes;
+ if (ord->_noerror) {
+ if (size > 0) {
+ *bufp++ = '!';
+ --size;
+ }
+ else {
+ WARN_STATIC_BUFFER();
+ }
+ }
if (ord->_persistent) {
if (size > 0) {
*bufp++ = '@';
@@ -159,6 +163,7 @@ order *copy_order(const order * src)
order *ord = (order *)malloc(sizeof(order));
ord->next = NULL;
ord->_persistent = src->_persistent;
+ ord->_noerror = src->_noerror;
ord->data = src->data;
++ord->data->_refcount;
return ord;
@@ -280,7 +285,7 @@ void close_orders(void) {
}
static order *create_order_i(keyword_t kwd, const char *sptr, bool persistent,
- const struct locale *lang)
+ bool noerror, const struct locale *lang)
{
order *ord = NULL;
int lindex;
@@ -313,6 +318,7 @@ static order *create_order_i(keyword_t kwd, const char *sptr, bool persistent,
ord = (order *)malloc(sizeof(order));
ord->_persistent = persistent;
+ ord->_noerror = noerror;
ord->next = NULL;
ord->data = create_data(kwd, sptr, lindex);
@@ -373,7 +379,7 @@ order *create_order(keyword_t kwd, const struct locale * lang,
else {
zBuffer[0] = 0;
}
- return create_order_i(kwd, zBuffer, false, lang);
+ return create_order_i(kwd, zBuffer, false, false, lang);
}
order *parse_order(const char *s, const struct locale * lang)
@@ -386,11 +392,12 @@ order *parse_order(const char *s, const struct locale * lang)
if (*s != 0) {
keyword_t kwd;
const char *sptr;
- bool persistent = false;
+ bool persistent = false, noerror = false;
const char * p;
- while (*s == '@') {
- persistent = true;
+ while (*s == '!' || *s=='@') {
+ if (*s=='!') noerror = true;
+ else if (*s == '@') persistent = true;
++s;
}
sptr = s;
@@ -407,7 +414,7 @@ order *parse_order(const char *s, const struct locale * lang)
if (kwd != NOKEYWORD) {
while (isspace(*(unsigned char *)sptr)) ++sptr;
s = sptr;
- return create_order_i(kwd, s, persistent, lang);
+ return create_order_i(kwd, s, persistent, noerror, lang);
}
}
return NULL;
diff --git a/src/kernel/order.h b/src/kernel/order.h
index 7f4b00a5e..bf4d02982 100644
--- a/src/kernel/order.h
+++ b/src/kernel/order.h
@@ -37,6 +37,7 @@ extern "C" {
/* do not access this data: */
struct order_data *data;
bool _persistent;
+ bool _noerror;
} order;
/* constructor */
diff --git a/src/kernel/order.test.c b/src/kernel/order.test.c
index f5eb51c6f..876d75b1e 100644
--- a/src/kernel/order.test.c
+++ b/src/kernel/order.test.c
@@ -14,14 +14,13 @@ static void test_create_order(CuTest *tc) {
order *ord;
struct locale * lang;
- test_cleanup();
- lang = get_or_create_locale("en");
+ test_setup();
+ lang = test_create_locale();
- locale_setstring(lang, "keyword::move", "MOVE");
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, cmd, sizeof(cmd)));
CuAssertIntEquals(tc, K_MOVE, init_order(ord));
CuAssertStrEquals(tc, "NORTH", getstrtoken());
@@ -34,19 +33,44 @@ static void test_parse_order(CuTest *tc) {
order *ord;
struct locale * lang;
- test_cleanup();
- lang = get_or_create_locale("en");
+ test_setup();
+ lang = test_create_locale();
- locale_setstring(lang, "keyword::move", "MOVE");
- init_keyword(lang, K_MOVE, "MOVE");
ord = parse_order("MOVE NORTH", lang);
CuAssertPtrNotNull(tc, ord);
+ CuAssertTrue(tc, !ord->_noerror);
+ CuAssertTrue(tc, !ord->_persistent);
CuAssertIntEquals(tc, K_MOVE, getkeyword(ord));
- CuAssertStrEquals(tc, "MOVE NORTH", get_command(ord, cmd, sizeof(cmd)));
+ CuAssertStrEquals(tc, "move NORTH", get_command(ord, cmd, sizeof(cmd)));
CuAssertIntEquals(tc, K_MOVE, init_order(ord));
CuAssertStrEquals(tc, "NORTH", getstrtoken());
free_order(ord);
+
+ ord = parse_order("!MOVE NORTH", lang);
+ CuAssertPtrNotNull(tc, ord);
+ CuAssertTrue(tc, ord->_noerror);
+ CuAssertTrue(tc, !ord->_persistent);
+ free_order(ord);
+
+ ord = parse_order("@MOVE NORTH", lang);
+ CuAssertPtrNotNull(tc, ord);
+ CuAssertTrue(tc, !ord->_noerror);
+ CuAssertTrue(tc, ord->_persistent);
+ free_order(ord);
+
+ ord = parse_order("@!MOVE NORTH", lang);
+ CuAssertPtrNotNull(tc, ord);
+ CuAssertTrue(tc, ord->_noerror);
+ CuAssertTrue(tc, ord->_persistent);
+ free_order(ord);
+
+ ord = parse_order("!@MOVE NORTH", lang);
+ CuAssertPtrNotNull(tc, ord);
+ CuAssertTrue(tc, ord->_noerror);
+ CuAssertTrue(tc, ord->_persistent);
+ free_order(ord);
+
test_cleanup();
}
@@ -81,7 +105,7 @@ static void test_parse_make_temp(CuTest *tc) {
lang = get_or_create_locale("en");
locale_setstring(lang, keyword(K_MAKE), "MAKE");
locale_setstring(lang, keyword(K_MAKETEMP), "MAKETEMP");
- locale_setstring(lang, "TEMP", "TEMP");
+ locale_setstring(lang, parameters[P_TEMP], "TEMP");
init_locale(lang);
ord = parse_order("M T herp", lang);
@@ -156,9 +180,9 @@ static void test_replace_order(CuTest *tc) {
struct locale * lang;
test_cleanup();
- lang = get_or_create_locale("en");
- orig = create_order(K_MAKE, lang, 0);
- repl = create_order(K_ALLY, lang, 0);
+ lang = test_create_locale();
+ orig = create_order(K_MAKE, lang, NULL);
+ repl = create_order(K_ALLY, lang, NULL);
replace_order(&orders, orig, repl);
CuAssertPtrEquals(tc, 0, orders);
orders = orig;
@@ -171,6 +195,25 @@ static void test_replace_order(CuTest *tc) {
test_cleanup();
}
+static void test_get_command(CuTest *tc) {
+ struct locale * lang;
+ order *ord;
+ char buf[64];
+
+ test_setup();
+ lang = test_create_locale();
+ ord = create_order(K_MAKE, lang, "iron");
+ CuAssertStrEquals(tc, "make iron", get_command(ord, buf, sizeof(buf)));
+ ord->_noerror = true;
+ CuAssertStrEquals(tc, "!make iron", get_command(ord, buf, sizeof(buf)));
+ ord->_persistent = true;
+ CuAssertStrEquals(tc, "!@make iron", get_command(ord, buf, sizeof(buf)));
+ ord->_noerror = false;
+ CuAssertStrEquals(tc, "@make iron", get_command(ord, buf, sizeof(buf)));
+ free_order(ord);
+ test_cleanup();
+}
+
CuSuite *get_order_suite(void)
{
CuSuite *suite = CuSuiteNew();
@@ -183,5 +226,6 @@ CuSuite *get_order_suite(void)
SUITE_ADD_TEST(suite, test_replace_order);
SUITE_ADD_TEST(suite, test_skip_token);
SUITE_ADD_TEST(suite, test_getstrtoken);
+ SUITE_ADD_TEST(suite, test_get_command);
return suite;
}
diff --git a/src/kernel/pool.c b/src/kernel/pool.c
index 702f86e0f..8dfd589c3 100644
--- a/src/kernel/pool.c
+++ b/src/kernel/pool.c
@@ -40,11 +40,11 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
int get_resource(const unit * u, const resource_type * rtype)
{
assert(rtype);
- if (rtype->uget) {
- /* this resource is probably special */
- int i = rtype->uget(u, rtype);
- if (i >= 0)
- return i;
+ if (rtype == get_resourcetype(R_PEASANT)) {
+ return u->region->land ? u->region->land->peasants : 0;
+ }
+ else if (rtype == rt_find("hp")) {
+ return u->hp;
}
else if (rtype->uchange) {
/* this resource is probably special */
@@ -176,7 +176,7 @@ int count)
}
if (rtype->flags & RTF_POOLED && mode & ~(GET_SLACK | GET_RESERVE)) {
for (v = r->units; v && use < count; v = v->next)
- if (u != v && (v->items || rtype->uget)) {
+ if (u != v) {
int mask;
if ((u_race(v)->ec_flags & ECF_KEEP_ITEM))
@@ -234,8 +234,6 @@ use_pooled(unit * u, const resource_type * rtype, unsigned int mode, int count)
int mask;
if ((u_race(v)->ec_flags & ECF_KEEP_ITEM))
continue;
- if (v->items == NULL && rtype->uget == NULL)
- continue;
if (v->faction == f) {
mask = (mode >> 3) & (GET_SLACK | GET_RESERVE);
diff --git a/src/kernel/race.c b/src/kernel/race.c
index 077e03b28..a2c37d87d 100644
--- a/src/kernel/race.c
+++ b/src/kernel/race.c
@@ -54,6 +54,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
/* libc includes */
#include
#include
+#include
#include
#include
#include
@@ -64,7 +65,7 @@ race *races;
int num_races = 0;
static int rc_changes = 1;
-static const char *racenames[MAXRACES] = {
+const char *racenames[MAXRACES] = {
"dwarf", "elf", NULL, "goblin", "human", "troll", "demon", "insect",
"halfling", "cat", "aquarian", "orc", "snotling", "undead", NULL,
"youngdragon", "dragon", "wyrm", "ent", "catdragon", "dracoid",
@@ -94,6 +95,7 @@ enum {
RCO_TRADEHERB
};
+
static void rc_setoption(race *rc, int k, const char *value) {
unsigned char key = (unsigned char)k;
int i;
@@ -166,7 +168,8 @@ const struct race *findrace(const char *s, const struct locale *lang)
const struct race *get_race(race_t rt) {
const char * name;
- assert(rt>=0 && rt < MAXRACES);
+ assert(rt >= 0);
+ assert(rt < MAXRACES);
name = racenames[rt];
if (!name) {
return NULL;
@@ -323,6 +326,17 @@ bool rc_changed(int *cache) {
return false;
}
+bool rc_can_use(const struct race *rc, const struct item_type *itype)
+{
+ if (itype->mask_allow) {
+ return (itype->mask_allow & rc->mask_item) != 0;
+ }
+ if (itype->mask_deny) {
+ return (itype->mask_deny & rc->mask_item) == 0;
+ }
+ return true;
+}
+
race *rc_create(const char *zName)
{
race *rc;
@@ -471,11 +485,9 @@ void rc_set_param(struct race *rc, const char *key, const char *value) {
}
}
-const char* rc_name(const race * rc, name_t n, char *name, size_t size) {
+const char* rc_key(const char *rcname, name_t n, char *name, size_t size)
+{
const char * postfix = 0;
- if (!rc) {
- return NULL;
- }
switch (n) {
case NAME_SINGULAR: postfix = ""; break;
case NAME_PLURAL: postfix = "_p"; break;
@@ -484,12 +496,20 @@ const char* rc_name(const race * rc, name_t n, char *name, size_t size) {
default: assert(!"invalid name_t enum in rc_name_s");
}
if (postfix) {
- snprintf(name, size, "race::%s%s", rc->_name, postfix);
+ snprintf(name, size, "race::%s%s", rcname, postfix);
return name;
}
return NULL;
}
+const char* rc_name(const race * rc, name_t n, char *name, size_t size)
+{
+ if (!rc) {
+ return NULL;
+ }
+ return rc_key(rc->_name, n, name, size);
+}
+
const char *rc_name_s(const race * rc, name_t n)
{
static char name[64]; /* FIXME: static return value */
diff --git a/src/kernel/race.h b/src/kernel/race.h
index f14b8e54f..5c320ea05 100644
--- a/src/kernel/race.h
+++ b/src/kernel/race.h
@@ -48,8 +48,7 @@ extern "C" {
struct spellref;
struct locale;
struct rcoption;
-
- extern int num_races;
+ struct item_type;
typedef enum {
RC_DWARF, /* 0 - Zwerg */
@@ -102,6 +101,9 @@ extern "C" {
NORACE = -1
} race_t;
+ extern int num_races;
+ extern const char *racenames[MAXRACES];
+
typedef struct att {
int type;
union {
@@ -140,6 +142,7 @@ extern "C" {
int flags;
int battle_flags;
int ec_flags;
+ int mask_item;
struct att attack[RACE_ATTACKS];
signed char bonus[MAXSKILLS];
@@ -174,8 +177,11 @@ extern "C" {
const race *rc_find(const char *);
void free_races(void);
+ bool rc_can_use(const struct race *rc, const struct item_type *itype);
+
typedef enum name_t { NAME_SINGULAR, NAME_PLURAL, NAME_DEFINITIVE, NAME_CATEGORY } name_t;
const char * rc_name_s(const race *rc, name_t n);
+ const char * rc_key(const char *rcname, name_t n, char *name, size_t size);
const char * rc_name(const race *rc, name_t n, char *name, size_t size);
void rc_set_param(struct race *rc, const char *key, const char *value);
diff --git a/src/kernel/race.test.c b/src/kernel/race.test.c
index 07ecbdd45..2db76a6fd 100644
--- a/src/kernel/race.test.c
+++ b/src/kernel/race.test.c
@@ -1,10 +1,13 @@
#include
#include
#include "race.h"
-#include
+#include "item.h"
+
#include
+#include
#include
+#include
#include
static void test_rc_name(CuTest *tc) {
@@ -100,6 +103,54 @@ static void test_rc_set_param(CuTest *tc) {
test_cleanup();
}
+static void test_rc_can_use(CuTest *tc) {
+ race *rc;
+ item_type *itype;
+
+ test_setup();
+ rc = test_create_race("goblin");
+ itype = test_create_itemtype("plate");
+ CuAssertTrue(tc, rc_can_use(rc, itype));
+
+ /* default case. all items and races in E2 */
+ itype->mask_deny = 0;
+ rc->mask_item = 0;
+ CuAssertTrue(tc, rc_can_use(rc, itype));
+
+ /* some race is forbidden from using this item. */
+ itype->mask_deny = 1;
+
+ /* we are not that race. */
+ rc->mask_item = 2;
+ CuAssertTrue(tc, rc_can_use(rc, itype));
+
+ /* we are that race */
+ rc->mask_item = 1;
+ CuAssertTrue(tc, ! rc_can_use(rc, itype));
+
+ /* we are not a special race at all */
+ rc->mask_item = 0;
+ CuAssertTrue(tc, rc_can_use(rc, itype));
+
+ /* only one race is allowed to use this item */
+ itype->mask_deny = 0;
+ itype->mask_allow = 1;
+
+ /* we are not that race */
+ rc->mask_item = 2;
+ CuAssertTrue(tc, ! rc_can_use(rc, itype));
+
+ /* we are that race */
+ rc->mask_item = 1;
+ CuAssertTrue(tc, rc_can_use(rc, itype));
+
+ /* we are not special */
+ rc->mask_item = 0;
+ CuAssertTrue(tc, ! rc_can_use(rc, itype));
+
+ test_cleanup();
+}
+
CuSuite *get_race_suite(void)
{
CuSuite *suite = CuSuiteNew();
@@ -109,6 +160,7 @@ CuSuite *get_race_suite(void)
SUITE_ADD_TEST(suite, test_rc_defaults);
SUITE_ADD_TEST(suite, test_rc_find);
SUITE_ADD_TEST(suite, test_rc_set_param);
+ SUITE_ADD_TEST(suite, test_rc_can_use);
return suite;
}
diff --git a/src/kernel/region.c b/src/kernel/region.c
index 5223d8bf8..5cb86ff47 100644
--- a/src/kernel/region.c
+++ b/src/kernel/region.c
@@ -38,6 +38,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include "unit.h"
/* util includes */
+#include
#include
#include
#include
@@ -697,6 +698,7 @@ void r_setdemand(region * r, const luxury_type * ltype, int value)
d = *dp;
if (!d) {
d = *dp = malloc(sizeof(struct demand));
+ assert_alloc(d);
d->next = NULL;
d->type = ltype;
}
@@ -768,6 +770,7 @@ region *new_region(int x, int y, struct plane *pl, int uid)
return r;
}
r = calloc(1, sizeof(region));
+ assert_alloc(r);
r->x = x;
r->y = y;
r->uid = uid;
@@ -1077,8 +1080,7 @@ void terraform_region(region * r, const terrain_type * terrain)
if (!fval(terrain, LAND_REGION)) {
region_setinfo(r, NULL);
- if (r->land != NULL) {
- i_freeall(&r->land->items);
+ if (r->land) {
free_land(r->land);
r->land = NULL;
}
@@ -1098,7 +1100,6 @@ void terraform_region(region * r, const terrain_type * terrain)
for (d = 0; d != MAXDIRECTIONS; ++d) {
rsetroad(r, d, 0);
}
- i_freeall(&r->land->items);
}
else {
static struct surround {
@@ -1173,11 +1174,6 @@ void terraform_region(region * r, const terrain_type * terrain)
if (fval(terrain, LAND_REGION)) {
const item_type *itype = NULL;
- char equip_hash[64];
-
- /* TODO: put the equipment in struct terrain, faster */
- sprintf(equip_hash, "terrain_%s", terrain->_name);
- equip_items(&r->land->items, get_equipment(equip_hash));
if (r->terrain->herbs) {
int len = 0;
@@ -1227,7 +1223,7 @@ void terraform_region(region * r, const terrain_type * terrain)
if (!fval(r, RF_CHAOTIC)) {
int peasants;
- peasants = (region_maxworkers(r) * (20 + dice_rand("6d10"))) / 100;
+ peasants = (region_maxworkers(r) * (20 + dice(6, 10))) / 100;
rsetpeasants(r, MAX(100, peasants));
rsetmoney(r, rpeasants(r) * ((wage(r, NULL, NULL,
INT_MAX) + 1) + rng_int() % 5));
@@ -1395,8 +1391,8 @@ faction *update_owners(region * r)
faction *f = NULL;
assert(rule_region_owners());
if (r->land) {
- building *bowner = largestbuilding(r, &cmp_current_owner, false);
- building *blargest = largestbuilding(r, &cmp_taxes, false);
+ building *bowner = largestbuilding(r, cmp_current_owner, false);
+ building *blargest = largestbuilding(r, cmp_taxes, false);
if (blargest) {
if (!bowner || bowner->size < blargest->size) {
/* region owners update? */
@@ -1502,6 +1498,7 @@ int owner_change(const region * r)
bool is_mourning(const region * r, int in_turn)
{
int change = owner_change(r);
- return (change == in_turn - 1 && r->land->ownership->last_owner && r->land->ownership->owner
- && r->land->ownership->last_owner != r->land->ownership->owner);
+ return (change == in_turn - 1 && r->land &&
+ r->land->ownership->last_owner && r->land->ownership->owner &&
+ r->land->ownership->last_owner != r->land->ownership->owner);
}
diff --git a/src/kernel/region.h b/src/kernel/region.h
index 9fa1a2daa..e3204d129 100644
--- a/src/kernel/region.h
+++ b/src/kernel/region.h
@@ -66,7 +66,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
struct faction;
struct gamedata;
-#define MORALE_TAX_FACTOR 0.005 /* 0.5% tax per point of morale */
+#define MORALE_TAX_FACTOR 200 /* 0.5% tax per point of morale, 1 silver per 200 */
#define MORALE_MAX 10 /* Maximum morale allowed */
#define MORALE_DEFAULT 1 /* Morale of peasants when they are conquered for the first time */
#define MORALE_TAKEOVER 0 /* Morale of peasants after they lose their lord */
@@ -105,7 +105,6 @@ extern "C" {
int peasants;
int newpeasants;
int money;
- struct item *items; /* items that can be claimed */
struct region_owner *ownership;
} land_region;
diff --git a/src/kernel/resources.c b/src/kernel/resources.c
index 8945e34c2..842cb83ba 100644
--- a/src/kernel/resources.c
+++ b/src/kernel/resources.c
@@ -11,10 +11,11 @@
*/
#include
-#include
#include "resources.h"
/* kernel includes */
+#include
+#include
#include "build.h"
#include "item.h"
#include "region.h"
@@ -193,16 +194,6 @@ struct rawmaterial *rm_get(region * r, const struct resource_type *rtype)
return rm;
}
-struct rawmaterial_type *rmt_find(const char *str)
-{
- resource_type *rtype = rt_find(str);
- if (!rtype && strncmp(str, "rm_", 3) == 0) {
- rtype = rt_find(str+3);
- }
- assert(rtype);
- return rtype ? rtype->raw : NULL;
-}
-
struct rawmaterial_type *rmt_get(const struct resource_type *rtype)
{
return rtype->raw;
@@ -222,3 +213,20 @@ struct rawmaterial_type *rmt_create(struct resource_type *rtype)
rmtype->visible = visible_default;
return rmtype;
}
+
+int limit_resource(const struct region *r, const resource_type *rtype)
+{
+ assert(!rtype->raw);
+ if (callbacks.limit_resource) {
+ return callbacks.limit_resource(r, rtype);
+ }
+ return -1;
+}
+
+void produce_resource(struct region *r, const struct resource_type *rtype, int amount)
+{
+ assert(!rtype->raw);
+ if (callbacks.produce_resource) {
+ callbacks.produce_resource(r, rtype, amount);
+ }
+}
diff --git a/src/kernel/resources.h b/src/kernel/resources.h
index 04e122f76..2daa44dd8 100644
--- a/src/kernel/resources.h
+++ b/src/kernel/resources.h
@@ -15,8 +15,11 @@
extern "C" {
#endif
+#include
+
struct building_type;
struct race;
+ struct region;
enum {
RM_USED = 1 << 0, /* resource has been used */
@@ -25,42 +28,31 @@ extern "C" {
typedef struct rawmaterial {
const struct resource_type *rtype;
-#ifdef LOMEM
- int amount:16;
- int level:8;
- int flags:8;
- int base:8;
- int divisor:8;
- int startlevel:8;
-#else
int amount;
int level;
int flags;
int base;
int divisor;
int startlevel;
-#endif
struct rawmaterial *next;
} rawmaterial;
- typedef int(*rlimit_limit) (const struct region * r,
- const struct resource_type * rtype);
- typedef void(*rlimit_produce) (struct region * r,
- const struct resource_type * rtype, int n);
+ /* resource-limits for regions */
+ typedef enum resource_modifier_type {
+ RMT_END, /* array terminator */
+ RMT_PROD_SKILL, /* bonus on resource production skill */
+ RMT_PROD_SAVE, /* fractional multiplier when produced */
+ RMT_PROD_REQUIRE, /* building or race is required to produce this item */
+ RMT_USE_SAVE, /* fractional multiplier when used to manufacture something */
+ } resource_modifier_type;
typedef struct resource_mod {
+ resource_modifier_type type;
variant value;
const struct building_type *btype;
const struct race *race;
- unsigned int flags;
} resource_mod;
- typedef struct resource_limit {
- rlimit_limit limit;
- rlimit_produce produce;
- resource_mod *modifiers;
- } resource_limit;
-
typedef struct rawmaterial_type {
const struct resource_type *rtype;
@@ -76,13 +68,15 @@ extern "C" {
void terraform_resources(struct region *r);
struct rawmaterial *rm_get(struct region *,
const struct resource_type *);
- struct rawmaterial_type *rmt_find(const char *str);
struct rawmaterial_type *rmt_get(const struct resource_type *);
struct rawmaterial *add_resource(struct region *r, int level,
int base, int divisor, const struct resource_type *rtype);
struct rawmaterial_type *rmt_create(struct resource_type *rtype);
+ int limit_resource(const struct region *r, const struct resource_type *rtype);
+ void produce_resource(struct region *r, const struct resource_type *rtype, int amount);
+
#ifdef __cplusplus
}
#endif
diff --git a/src/kernel/rules.c b/src/kernel/rules.c
new file mode 100644
index 000000000..c7499fe0c
--- /dev/null
+++ b/src/kernel/rules.c
@@ -0,0 +1,12 @@
+#include
+#include "rules.h"
+
+int write_rules(const char *filename) {
+ return -1;
+}
+
+int read_rules(const char *filename)
+{
+ return -1;
+}
+
diff --git a/src/kernel/rules.h b/src/kernel/rules.h
new file mode 100644
index 000000000..98f0bf240
--- /dev/null
+++ b/src/kernel/rules.h
@@ -0,0 +1,5 @@
+#pragma once
+
+int read_rules(const char *filename);
+int write_rules(const char * filename);
+
diff --git a/src/kernel/save.c b/src/kernel/save.c
index c9bdb2f2e..39f2a129f 100644
--- a/src/kernel/save.c
+++ b/src/kernel/save.c
@@ -52,6 +52,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include
/* util includes */
+#include
#include
#include
#include
@@ -243,7 +244,7 @@ static faction *factionorders(void)
/* TODO: +1 ist ein Workaround, weil cturn erst in process_orders
* incrementiert wird. */
- f->lastorders = global.data_turn + 1;
+ f->lastorders = turn + 1;
}
else {
@@ -646,6 +647,7 @@ unit *read_unit(struct gamedata *data)
}
else {
u = calloc(sizeof(unit), 1);
+ assert_alloc(u);
u->no = n;
uhash(u);
}
@@ -655,10 +657,7 @@ unit *read_unit(struct gamedata *data)
if (f != u->faction) {
u_setfaction(u, f);
}
- if (u->faction) {
- ++u->faction->no_units;
- }
- else {
+ if (!u->faction) {
log_error("unit %s has faction == NULL", itoa36(u->no));
return 0;
}
@@ -1022,7 +1021,9 @@ static region *readregion(struct gamedata *data, int x, int y)
if (!r->land->demands) {
fix_demand(r);
}
- read_items(data->store, &r->land->items);
+ if (data->version < NOLANDITEM_VERSION) {
+ read_items(data->store, NULL);
+ }
if (data->version >= REGIONOWNER_VERSION) {
READ_INT(data->store, &n);
region_set_morale(r, MAX(0, (short)n), -1);
@@ -1096,7 +1097,6 @@ void writeregion(struct gamedata *data, const region * r)
WRITE_INT(data->store, demand->value);
}
WRITE_TOK(data->store, "end");
- write_items(data->store, r->land->items);
WRITE_SECTION(data->store);
#if RELEASE_VERSION>=REGIONOWNER_VERSION
WRITE_INT(data->store, region_get_morale(r));
@@ -1122,9 +1122,7 @@ static ally **addally(const faction * f, ally ** sfp, int aid, int state)
ally *sf;
state &= ~HELP_OBSERVE;
-#ifndef REGIONOWNERS
state &= ~HELP_TRAVEL;
-#endif
state &= HelpMask();
if (state == 0)
@@ -1637,7 +1635,6 @@ int read_game(gamedata *data) {
}
read_attribs(data, &global.attribs, NULL);
READ_INT(store, &turn);
- global.data_turn = turn;
log_debug(" - reading turn %d", turn);
rng_init(turn);
READ_INT(store, NULL); /* max_unique_id = ignore */
diff --git a/src/kernel/ship.c b/src/kernel/ship.c
index b9ac0b170..220c16619 100644
--- a/src/kernel/ship.c
+++ b/src/kernel/ship.c
@@ -37,13 +37,15 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include
#include
#include
+#include
#include
-#include
#include
#include
#include
+#include
+#include
/* libc includes */
#include
@@ -51,7 +53,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include
#include
-selist *shiptypes = NULL;
+selist *shiptypes = NULL; /* do not use this list for searching*/
+static critbit_tree cb_shiptypes; /* use this trie instead */
static local_names *snames;
@@ -60,9 +63,7 @@ const ship_type *findshiptype(const char *name, const struct locale *lang)
local_names *sn = snames;
variant var;
- while (sn) {
- if (sn->lang == lang)
- break;
+ while (sn && sn->lang != lang) {
sn = sn->next;
}
if (!sn) {
@@ -89,29 +90,43 @@ const ship_type *findshiptype(const char *name, const struct locale *lang)
static ship_type *st_find_i(const char *name)
{
- selist *ql;
- int qi;
+ const char *match;
+ ship_type *st = NULL;
- for (qi = 0, ql = shiptypes; ql; selist_advance(&ql, &qi, 1)) {
- ship_type *stype = (ship_type *)selist_get(ql, qi);
- if (strcmp(stype->_name, name) == 0) {
- return stype;
- }
+ match = cb_find_str(&cb_shiptypes, name);
+ if (match) {
+ cb_get_kv(match, &st, sizeof(st));
}
- return NULL;
+ return st;
}
const ship_type *st_find(const char *name) {
- return st_find_i(name);
+ ship_type *st = st_find_i(name);
+ if (!st) {
+ log_warning("st_find: could not find ship '%s'\n", name);
+ }
+ return st;
+}
+
+static void st_register(ship_type *stype) {
+ size_t len;
+ char data[64];
+
+ selist_push(&shiptypes, (void *)stype);
+
+ len = cb_new_kv(stype->_name, strlen(stype->_name), &stype, sizeof(stype), data);
+ assert(len <= sizeof(data));
+ cb_insert(&cb_shiptypes, data, len);
}
ship_type *st_get_or_create(const char * name) {
ship_type * st = st_find_i(name);
+ assert(!snames);
if (!st) {
st = (ship_type *)calloc(sizeof(ship_type), 1);
st->_name = strdup(name);
st->storm = 1.0;
- selist_push(&shiptypes, (void *)st);
+ st_register(st);
}
return st;
}
@@ -234,8 +249,9 @@ void remove_ship(ship ** slist, ship * sh)
void free_ship(ship * s)
{
- while (s->attribs)
+ while (s->attribs) {
a_remove(&s->attribs, s->attribs);
+ }
free(s->name);
free(s->display);
free(s);
@@ -250,6 +266,7 @@ static void free_shiptype(void *ptr) {
}
void free_shiptypes(void) {
+ cb_clear(&cb_shiptypes);
selist_foreach(shiptypes, free_shiptype);
selist_free(shiptypes);
shiptypes = 0;
diff --git a/src/kernel/skills.c b/src/kernel/skills.c
index 488800115..b951b77ba 100644
--- a/src/kernel/skills.c
+++ b/src/kernel/skills.c
@@ -62,8 +62,7 @@ attrib_type at_skillmod = {
ATF_PRESERVE
};
-attrib *make_skillmod(skill_t sk, unsigned int flags, skillmod_fun special,
- double multiplier, int bonus)
+attrib *make_skillmod(skill_t sk, skillmod_fun special, double multiplier, int bonus)
{
attrib *a = a_new(&at_skillmod);
skillmod_data *smd = (skillmod_data *)a->data.v;
@@ -72,22 +71,19 @@ attrib *make_skillmod(skill_t sk, unsigned int flags, skillmod_fun special,
smd->special = special;
smd->bonus = bonus;
smd->multiplier = multiplier;
- smd->flags = flags;
return a;
}
int
-skillmod(const attrib * a, const unit * u, const region * r, skill_t sk,
-int value, int flags)
+skillmod(const unit * u, const region * r, skill_t sk, int value)
{
+ const attrib * a = u->attribs;
for (a = a_find((attrib *)a, &at_skillmod); a && a->type == &at_skillmod;
a = a->next) {
skillmod_data *smd = (skillmod_data *)a->data.v;
if (smd->skill != NOSKILL && smd->skill != sk)
continue;
- if (flags != SMF_ALWAYS && (smd->flags & flags) == 0)
- continue;
if (smd->special) {
value = smd->special(u, r, sk, value);
if (value < 0)
diff --git a/src/kernel/skills.h b/src/kernel/skills.h
index 192030dcf..1261a7ea9 100644
--- a/src/kernel/skills.h
+++ b/src/kernel/skills.h
@@ -15,27 +15,21 @@
#include
+struct race;
+struct unit;
+struct region;
+struct attrib;
+struct attrib_type;
+
#ifdef __cplusplus
extern "C" {
#endif
- /* skillmod_data::flags -- wann gilt der modifier? */
-#define SMF_ALWAYS (1<<0) /* immer */
-#define SMF_PRODUCTION (1<<1) /* fr Produktion - am gebude, an der einheit */
-#define SMF_RIDING (1<<2) /* Bonus fr berittene - an der rasse */
-
typedef struct skill {
-#ifdef LOMEM
- int id:8;
- unsigned int level:8;
- unsigned int weeks:8;
- unsigned int old:8;
-#else
- int id;
+ skill_t id;
int level;
int weeks;
int old;
-#endif
} skill;
typedef int(*skillmod_fun) (const struct unit *, const struct region *,
@@ -46,25 +40,23 @@ extern "C" {
double multiplier;
int number;
int bonus;
- int flags;
} skillmod_data;
- extern struct attrib_type at_skillmod;
- extern int rc_skillmod(const struct race *rc, const struct region *r,
- skill_t sk);
- extern int skillmod(const struct attrib *a, const struct unit *u,
- const struct region *r, skill_t sk, int value, int flags);
- extern struct attrib *make_skillmod(skill_t sk, unsigned int flags,
- skillmod_fun special, double multiplier, int bonus);
- extern int level_days(int level);
- extern int level(int days);
+ extern struct attrib_type at_skillmod;
+
+ int rc_skillmod(const struct race *rc, const struct region *r, skill_t sk);
+ int skillmod(const struct unit *u, const struct region *r, skill_t sk, int value);
+ struct attrib *make_skillmod(skill_t sk, skillmod_fun special, double multiplier, int bonus);
+
+ int level_days(int level);
+ int level(int days);
#define skill_level(level) (level)
- extern void reduce_skill(struct unit *u, skill * sv, unsigned int change);
- extern int skill_weeks(int level);
- extern int skill_compare(const skill * sk, const skill * sc);
+ void reduce_skill(struct unit *u, skill * sv, unsigned int change);
+ int skill_weeks(int level);
+ int skill_compare(const skill * sk, const skill * sc);
- extern void sk_set(skill * sv, int level);
+ void sk_set(skill * sv, int level);
#ifdef __cplusplus
}
diff --git a/src/kernel/spell.c b/src/kernel/spell.c
index 212b0a7d2..0abb487f7 100644
--- a/src/kernel/spell.c
+++ b/src/kernel/spell.c
@@ -33,6 +33,51 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include
#include
+
+static critbit_tree cb_spell_fun;
+void add_spellcast(const char *sname, spell_f fun)
+{
+ size_t len;
+ char data[64];
+
+ len = cb_new_kv(sname, strlen(sname), &fun, sizeof(fun), data);
+ assert(len <= sizeof(data));
+ cb_insert(&cb_spell_fun, data, len);
+}
+
+spell_f get_spellcast(const char *sname)
+{
+ void * match;
+ spell_f result = NULL;
+
+ if (cb_find_prefix(&cb_spell_fun, sname, strlen(sname) + 1, &match, 1, 0)) {
+ cb_get_kv(match, &result, sizeof(result));
+ }
+ return result;
+}
+
+static critbit_tree cb_fumble_fun;
+void add_fumble(const char *sname, fumble_f fun)
+{
+ size_t len;
+ char data[64];
+
+ len = cb_new_kv(sname, strlen(sname), &fun, sizeof(fun), data);
+ assert(len <= sizeof(data));
+ cb_insert(&cb_fumble_fun, data, len);
+}
+
+fumble_f get_fumble(const char *sname)
+{
+ void * match;
+ fumble_f result = NULL;
+
+ if (cb_find_prefix(&cb_fumble_fun, sname, strlen(sname) + 1, &match, 1, 0)) {
+ cb_get_kv(match, &result, sizeof(result));
+ }
+ return result;
+}
+
static critbit_tree cb_spells;
selist * spells;
@@ -49,6 +94,8 @@ static void free_spell_cb(void *cbdata) {
}
void free_spells(void) {
+ cb_clear(&cb_fumble_fun);
+ cb_clear(&cb_spell_fun);
cb_clear(&cb_spells);
selist_foreach(spells, free_spell_cb);
selist_free(spells);
@@ -62,7 +109,7 @@ void add_spell(struct selist **slistp, spell * sp)
}
}
-spell * create_spell(const char * name, unsigned int id)
+spell * create_spell(const char * name)
{
spell * sp;
char buffer[64];
@@ -77,7 +124,6 @@ spell * create_spell(const char * name, unsigned int id)
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->id = id ? id : hashstring(name);
sp->sname = strdup(name);
add_spell(&spells, sp);
return sp;
@@ -121,31 +167,6 @@ spell *find_spell(const char *name)
return sp;
}
-spell *find_spellbyid(unsigned int id)
-{
- selist *ql;
- int qi;
-
- if (id == 0)
- return NULL;
- for (qi = 0, ql = spells; ql; selist_advance(&ql, &qi, 1)) {
- spell *sp = (spell *)selist_get(ql, qi);
- if (sp->id == id) {
- return sp;
- }
- }
- for (qi = 0, ql = spells; ql; selist_advance(&ql, &qi, 1)) {
- spell *sp = (spell *)selist_get(ql, qi);
- unsigned int hashid = hashstring(sp->sname);
- if (hashid == id) {
- return sp;
- }
- }
-
- log_warning("cannot find spell by id: %u\n", id);
- return NULL;
-}
-
struct spellref *spellref_create(spell *sp, const char *name)
{
spellref *spref = malloc(sizeof(spellref));
diff --git a/src/kernel/spell.h b/src/kernel/spell.h
index e7592f082..17a565fa6 100644
--- a/src/kernel/spell.h
+++ b/src/kernel/spell.h
@@ -34,15 +34,12 @@ extern "C" {
typedef void(*fumble_f)(const struct castorder * co);
typedef struct spell {
- unsigned int id;
char *sname;
char *syntax;
char *parameter;
int sptyp;
int rank; /* Reihenfolge der Zauber */
struct spell_component *components;
- spell_f cast;
- fumble_f fumble;
} spell;
typedef struct spellref {
@@ -50,15 +47,20 @@ extern "C" {
struct spell *sp;
} spellref;
+ void add_fumble(const char *sname, fumble_f fun);
+ fumble_f get_fumble(const char *sname);
+
+ void add_spellcast(const char *sname, spell_f fun);
+ spell_f get_spellcast(const char *sname);
+
struct spellref *spellref_create(struct spell *sp, const char *name);
void spellref_free(struct spellref *spref);
struct spell *spellref_get(struct spellref *spref);
int sp_antimagiczone(struct castorder *co);
- struct spell * create_spell(const char * name, unsigned int id);
+ struct spell * create_spell(const char * name);
struct spell * find_spell(const char *name);
- struct spell * find_spellbyid(unsigned int i);
void add_spell(struct selist **slistp, spell * sp);
void free_spells(void);
diff --git a/src/kernel/spell.test.c b/src/kernel/spell.test.c
index b500f94cc..e5a37fd65 100644
--- a/src/kernel/spell.test.c
+++ b/src/kernel/spell.test.c
@@ -19,7 +19,7 @@ static void test_create_a_spell(CuTest * tc)
CuAssertPtrEquals(tc, 0, spells);
CuAssertPtrEquals(tc, 0, find_spell("testspell"));
- sp = create_spell("testspell", 0);
+ sp = create_spell("testspell");
CuAssertPtrEquals(tc, sp, find_spell("testspell"));
CuAssertPtrNotNull(tc, spells);
test_cleanup();
@@ -37,8 +37,8 @@ static void test_create_duplicate_spell(CuTest * tc)
CuAssertPtrEquals(tc, 0, find_spell("testspell"));
- sp = create_spell("testspell", 0);
- CuAssertPtrEquals(tc, 0, create_spell("testspell", 0));
+ sp = create_spell("testspell");
+ CuAssertPtrEquals(tc, 0, create_spell("testspell"));
CuAssertPtrNotNull(tc, sl);
CuAssertStrEquals(tc, "create_spell: duplicate name '%s'", sl->s);
CuAssertPtrEquals(tc, 0, sl->next);
@@ -47,28 +47,6 @@ static void test_create_duplicate_spell(CuTest * tc)
test_cleanup();
}
-static void test_create_spell_with_id(CuTest * tc)
-{
- spell *sp;
- struct log_t *log;
- strlist *sl = 0;
-
- test_setup();
- test_log_stderr(0);
- log = test_log_start(LOG_CPERROR, &sl);
-
- CuAssertPtrEquals(tc, 0, find_spellbyid(42));
- sp = create_spell("testspell", 42);
- CuAssertPtrEquals(tc, sp, find_spellbyid(42));
- CuAssertPtrEquals(tc, 0, create_spell("testspell", 47));
- CuAssertPtrEquals(tc, 0, find_spellbyid(47));
- CuAssertPtrNotNull(tc, sl);
- CuAssertStrEquals(tc, "create_spell: duplicate name '%s'", sl->s);
- CuAssertPtrEquals(tc, 0, sl->next);
- test_log_stop(log, sl);
- test_cleanup();
-}
-
static void test_spellref(CuTest *tc)
{
spellref *ref;
@@ -79,19 +57,39 @@ static void test_spellref(CuTest *tc)
CuAssertPtrEquals(tc, NULL, ref->sp);
CuAssertStrEquals(tc, "hodor", ref->name);
CuAssertPtrEquals(tc, NULL, spellref_get(ref));
- sp = create_spell("hodor", 0);
+ sp = create_spell("hodor");
CuAssertPtrNotNull(tc, sp);
CuAssertPtrEquals(tc, sp, spellref_get(ref));
spellref_free(ref);
test_cleanup();
}
+void fumble_foo(const struct castorder *co) {
+ UNUSED_ARG(co);
+}
+
+void fumble_bar(const struct castorder *co) {
+ UNUSED_ARG(co);
+}
+
+static void test_fumbles(CuTest *tc)
+{
+ test_setup();
+ CuAssertTrue(tc, NULL==get_fumble("foo"));
+ add_fumble("foone", fumble_foo);
+ add_fumble("foozle", fumble_bar);
+ CuAssertTrue(tc, fumble_foo==get_fumble("foone"));
+ CuAssertTrue(tc, fumble_bar==get_fumble("foozle"));
+ CuAssertTrue(tc, NULL==get_fumble("foo"));
+ test_cleanup();
+}
+
CuSuite *get_spell_suite(void)
{
CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, test_spellref);
+ SUITE_ADD_TEST(suite, test_fumbles);
SUITE_ADD_TEST(suite, test_create_a_spell);
SUITE_ADD_TEST(suite, test_create_duplicate_spell);
- SUITE_ADD_TEST(suite, test_create_spell_with_id);
return suite;
}
diff --git a/src/kernel/spellbook.test.c b/src/kernel/spellbook.test.c
index 8b997557b..37f20cced 100644
--- a/src/kernel/spellbook.test.c
+++ b/src/kernel/spellbook.test.c
@@ -33,7 +33,7 @@ void test_named_spellbooks(CuTest * tc)
CuAssertPtrNotNull(tc, sb);
CuAssertStrEquals(tc, "spells", sb->name);
- sp = create_spell("testspell", 0);
+ sp = create_spell("testspell");
spellbook_add(sb, sp, 1);
CuAssertPtrNotNull(tc, sb->spells);
diff --git a/src/kernel/unit.c b/src/kernel/unit.c
index 595accba2..ab5f72f35 100644
--- a/src/kernel/unit.c
+++ b/src/kernel/unit.c
@@ -438,8 +438,13 @@ int remove_unit(unit ** ulist, unit * u)
*ulist = u->next;
}
- if (u->faction && u->faction->units == u) {
- u->faction->units = u->nextF;
+ if (u->faction) {
+ if (count_unit(u)) {
+ --u->faction->num_units;
+ }
+ if (u->faction->units == u) {
+ u->faction->units = u->nextF;
+ }
}
if (u->prevF) {
u->prevF->nextF = u->nextF;
@@ -1125,12 +1130,13 @@ struct building *inside_building(const struct unit *u)
void u_setfaction(unit * u, faction * f)
{
- int cnt = u->number;
if (u->faction == f)
return;
if (u->faction) {
- --u->faction->no_units;
- set_number(u, 0);
+ if (count_unit(u)) {
+ --u->faction->num_units;
+ u->faction->num_people -= u->number;
+ }
join_group(u, NULL);
free_orders(&u->orders);
set_order(&u->thisorder, NULL);
@@ -1162,14 +1168,19 @@ void u_setfaction(unit * u, faction * f)
if (u->region) {
update_interval(f, u->region);
}
- if (cnt) {
- set_number(u, cnt);
- }
- if (f) {
- ++f->no_units;
+ if (f && count_unit(u)) {
+ ++f->num_units;
+ f->num_people += u->number;
}
}
+bool count_unit(const unit *u)
+{
+ const race *rc = u_race(u);
+ /* spells are invisible. units we cannot see do not count to our limit */
+ return rc == NULL || (rc->flags & RCF_INVISIBLE) == 0;
+}
+
void set_number(unit * u, int count)
{
assert(count >= 0);
@@ -1178,10 +1189,10 @@ void set_number(unit * u, int count)
if (count == 0) {
u->flags &= ~(UFL_HERO);
}
- if (u->faction) {
+ if (u->faction && count_unit(u)) {
u->faction->num_people += count - u->number;
}
- u->number = (unsigned short)count;
+ u->number = count;
}
void remove_skill(unit * u, skill_t sk)
@@ -1322,8 +1333,9 @@ int get_modifier(const unit * u, skill_t sk, int level, const region * r, bool n
skill += rc_skillmod(u_race(u), r, sk);
skill += att_modification(u, sk);
-
- skill = skillmod(u->attribs, u, r, sk, skill, SMF_ALWAYS);
+ if (u->attribs) {
+ skill = skillmod(u, r, sk, skill);
+ }
if (fval(u, UFL_HUNGER)) {
if (sk == SK_SAILING && skill > 2) {
@@ -1484,6 +1496,8 @@ unit *create_unit(region * r, faction * f, int number, const struct race *urace,
unit *u = (unit *)calloc(1, sizeof(unit));
assert(urace);
+ u_setrace(u, urace);
+ u->irace = NULL;
if (f) {
assert(faction_alive(f));
u_setfaction(u, f);
@@ -1496,8 +1510,6 @@ unit *create_unit(region * r, faction * f, int number, const struct race *urace,
}
}
}
- u_setrace(u, urace);
- u->irace = NULL;
set_number(u, number);
@@ -1581,7 +1593,7 @@ unit *create_unit(region * r, faction * f, int number, const struct race *urace,
int maxheroes(const struct faction *f)
{
- int nsize = count_all(f);
+ int nsize = f->num_people;
if (nsize == 0)
return 0;
else {
@@ -1713,13 +1725,13 @@ int unit_max_hp(const unit * u)
int h;
double p;
static int config;
- static int rule_stamina;
+ static bool rule_stamina;
h = u_race(u)->hitpoints;
if (config_changed(&config)) {
- rule_stamina = config_get_int("rules.stamina", STAMINA_AFFECTS_HP);
+ rule_stamina = config_get_int("rules.stamina", 1)!=0;
}
- if (rule_stamina & 1) {
+ if (rule_stamina) {
p = pow(effskill(u, SK_STAMINA, u->region) / 2.0, 1.5) * 0.2;
h += (int)(h * p + 0.5);
}
@@ -1803,7 +1815,23 @@ const struct race *u_race(const struct unit *u)
void u_setrace(struct unit *u, const struct race *rc)
{
assert(rc);
- u->_race = rc;
+ if (!u->faction) {
+ u->_race = rc;
+ }
+ else {
+ int n = 0;
+ if (count_unit(u)) {
+ --n;
+ }
+ u->_race = rc;
+ if (count_unit(u)) {
+ ++n;
+ }
+ if (n != 0) {
+ u->faction->num_units += n;
+ u->faction->num_people += n * u->number;
+ }
+ }
}
void unit_add_spell(unit * u, sc_mage * m, struct spell * sp, int level)
diff --git a/src/kernel/unit.h b/src/kernel/unit.h
index 14096c872..8ae13c5e2 100644
--- a/src/kernel/unit.h
+++ b/src/kernel/unit.h
@@ -130,6 +130,7 @@ extern "C" {
int weight(const struct unit *u);
void renumber_unit(struct unit *u, int no);
+ bool count_unit(const unit *u); /* unit counts towards faction.num_units and faction.num_people */
const struct race *u_irace(const struct unit *u);
const struct race *u_race(const struct unit *u);
diff --git a/src/kernel/unit.test.c b/src/kernel/unit.test.c
index e1654b821..096da9d62 100644
--- a/src/kernel/unit.test.c
+++ b/src/kernel/unit.test.c
@@ -153,42 +153,37 @@ static void test_unit_name(CuTest *tc) {
static void test_unit_name_from_race(CuTest *tc) {
unit *u;
- struct locale *lang;
- test_cleanup();
- test_create_world();
- u = test_create_unit(test_create_faction(test_create_race("human")), findregion(0, 0));
+ test_setup();
+ u = test_create_unit(test_create_faction(test_create_race("human")), test_create_region(0, 0, NULL));
renumber_unit(u, 666);
unit_setname(u, NULL);
- lang = get_or_create_locale("de");
- locale_setstring(lang, rc_name_s(u->_race, NAME_SINGULAR), "Mensch");
- locale_setstring(lang, rc_name_s(u->_race, NAME_PLURAL), "Menschen");
- CuAssertStrEquals(tc, "Mensch (ii)", unitname(u));
- CuAssertStrEquals(tc, "Mensch", unit_getname(u));
+ CuAssertStrEquals(tc, "human (ii)", unitname(u));
+ CuAssertStrEquals(tc, "human", unit_getname(u));
u->number = 2;
- CuAssertStrEquals(tc, "Menschen (ii)", unitname(u));
- CuAssertStrEquals(tc, "Menschen", unit_getname(u));
+ CuAssertStrEquals(tc, "human_p (ii)", unitname(u));
+ CuAssertStrEquals(tc, "human_p", unit_getname(u));
test_cleanup();
}
static void test_update_monster_name(CuTest *tc) {
unit *u;
- struct locale *lang;
+ race *rc;
- test_cleanup();
- test_create_world();
- u = test_create_unit(test_create_faction(test_create_race("human")), findregion(0, 0));
- lang = get_or_create_locale("de");
- locale_setstring(lang, rc_name_s(u->_race, NAME_SINGULAR), "Mensch");
- locale_setstring(lang, rc_name_s(u->_race, NAME_PLURAL), "Menschen");
+ test_setup();
+ rc = test_create_race("human");
+ u = test_create_unit(test_create_faction(rc), test_create_region(0, 0, NULL));
unit_setname(u, "Hodor");
CuAssertTrue(tc, !unit_name_equals_race(u));
- unit_setname(u, "Menschling");
+ unit_setname(u, "humanitarian");
+ CuAssertTrue(tc, !unit_name_equals_race(u));
+
+ unit_setname(u, "huma");
CuAssertTrue(tc, !unit_name_equals_race(u));
unit_setname(u, rc_name_s(u->_race, NAME_SINGULAR));
@@ -197,12 +192,6 @@ 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));
- unit_setname(u, "Mensch");
- CuAssertTrue(tc, unit_name_equals_race(u));
-
- unit_setname(u, "Menschen");
- CuAssertTrue(tc, unit_name_equals_race(u));
-
test_cleanup();
}
@@ -256,19 +245,19 @@ static void test_skillmod(CuTest *tc) {
set_level(u, SK_ARMORER, 5);
CuAssertIntEquals(tc, 5, effskill(u, SK_ARMORER, 0));
- a_add(&u->attribs, a = make_skillmod(SK_ARMORER, SMF_ALWAYS, 0, 2.0, 0));
+ a_add(&u->attribs, a = make_skillmod(SK_ARMORER, 0, 2.0, 0));
CuAssertIntEquals(tc, 10, effskill(u, SK_ARMORER, 0));
a_remove(&u->attribs, a);
- a_add(&u->attribs, a = make_skillmod(NOSKILL, SMF_ALWAYS, 0, 2.0, 0)); /* NOSKILL means any skill */
+ a_add(&u->attribs, a = make_skillmod(NOSKILL, 0, 2.0, 0)); /* NOSKILL means any skill */
CuAssertIntEquals(tc, 10, effskill(u, SK_ARMORER, 0));
a_remove(&u->attribs, a);
- a_add(&u->attribs, a = make_skillmod(SK_ARMORER, SMF_ALWAYS, 0, 0, 2));
+ a_add(&u->attribs, a = make_skillmod(SK_ARMORER, 0, 0, 2));
CuAssertIntEquals(tc, 7, effskill(u, SK_ARMORER, 0));
a_remove(&u->attribs, a);
- a_add(&u->attribs, a = make_skillmod(SK_ARMORER, SMF_ALWAYS, cb_skillmod, 0, 0));
+ a_add(&u->attribs, a = make_skillmod(SK_ARMORER, cb_skillmod, 0, 0));
CuAssertIntEquals(tc, 8, effskill(u, SK_ARMORER, 0));
a_remove(&u->attribs, a);
@@ -519,6 +508,43 @@ static void test_heal_factor(CuTest *tc) {
test_cleanup();
}
+static void test_unlimited_units(CuTest *tc) {
+ race *rc;
+ faction *f;
+ unit *u;
+
+ test_setup();
+ f = test_create_faction(NULL);
+ rc = test_create_race("spell");
+ rc->flags |= RCF_INVISIBLE;
+ CuAssertIntEquals(tc, 0, f->num_units);
+ CuAssertIntEquals(tc, 0, f->num_people);
+ u = test_create_unit(f, test_create_region(0, 0, NULL));
+ CuAssertTrue(tc, count_unit(u));
+ CuAssertIntEquals(tc, 1, f->num_units);
+ CuAssertIntEquals(tc, 1, f->num_people);
+ u_setfaction(u, NULL);
+ CuAssertIntEquals(tc, 0, f->num_units);
+ CuAssertIntEquals(tc, 0, f->num_people);
+ u_setfaction(u, f);
+ CuAssertIntEquals(tc, 1, f->num_units);
+ CuAssertIntEquals(tc, 1, f->num_people);
+ u_setrace(u, rc);
+ CuAssertTrue(tc, !count_unit(u));
+ CuAssertIntEquals(tc, 0, f->num_units);
+ CuAssertIntEquals(tc, 0, f->num_people);
+ scale_number(u, 10);
+ CuAssertIntEquals(tc, 0, f->num_units);
+ CuAssertIntEquals(tc, 0, f->num_people);
+ u_setrace(u, f->race);
+ CuAssertIntEquals(tc, 1, f->num_units);
+ CuAssertIntEquals(tc, 10, f->num_people);
+ remove_unit(&u->region->units, u);
+ CuAssertIntEquals(tc, 0, f->num_units);
+ CuAssertIntEquals(tc, 0, f->num_people);
+ test_cleanup();
+}
+
CuSuite *get_unit_suite(void)
{
CuSuite *suite = CuSuiteNew();
@@ -534,6 +560,7 @@ CuSuite *get_unit_suite(void)
SUITE_ADD_TEST(suite, test_remove_units_with_dead_faction);
SUITE_ADD_TEST(suite, test_remove_empty_units_in_region);
SUITE_ADD_TEST(suite, test_names);
+ SUITE_ADD_TEST(suite, test_unlimited_units);
SUITE_ADD_TEST(suite, test_default_name);
SUITE_ADD_TEST(suite, test_skillmod);
SUITE_ADD_TEST(suite, test_skill_hunger);
diff --git a/src/kernel/version.c b/src/kernel/version.c
index 633fbf7bf..39f4f30e6 100644
--- a/src/kernel/version.c
+++ b/src/kernel/version.c
@@ -5,7 +5,7 @@
#ifndef ERESSEA_VERSION
/* the version number, if it was not passed to make with -D */
-#define ERESSEA_VERSION "3.11.0"
+#define ERESSEA_VERSION "3.12.0"
#endif
const char *eressea_version(void) {
diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c
index 737a12f66..9953f7335 100644
--- a/src/kernel/xmlreader.c
+++ b/src/kernel/xmlreader.c
@@ -30,6 +30,7 @@ without prior permission by the authors of Eressea.
#include "spellbook.h"
#include "calendar.h"
#include "prefix.h"
+#include "move.h"
#include "vortex.h"
@@ -120,6 +121,72 @@ static xmlChar *xml_cleanup_string(xmlChar * str)
return str;
}
+static resource_mod * xml_readmodifiers(xmlXPathObjectPtr result, xmlNodePtr node) {
+ /* reading eressea/resources/resource/modifier */
+ if (result->nodesetval != NULL && result->nodesetval->nodeNr > 0) {
+ int k;
+ resource_mod * modifiers =
+ calloc(result->nodesetval->nodeNr + 1, sizeof(resource_mod));
+ for (k = 0; k != result->nodesetval->nodeNr; ++k) {
+ xmlNodePtr node = result->nodesetval->nodeTab[k];
+ xmlChar *propValue;
+ building_type *btype = NULL;
+ const race *rc = NULL;
+
+ propValue = xmlGetProp(node, BAD_CAST "race");
+ if (propValue != NULL) {
+ rc = rc_find((const char *)propValue);
+ if (rc == NULL)
+ rc = rc_get_or_create((const char *)propValue);
+ xmlFree(propValue);
+ }
+ modifiers[k].race = rc;
+
+ propValue = xmlGetProp(node, BAD_CAST "building");
+ if (propValue != NULL) {
+ btype = bt_get_or_create((const char *)propValue);
+ xmlFree(propValue);
+ }
+ modifiers[k].btype = btype;
+
+ propValue = xmlGetProp(node, BAD_CAST "type");
+ assert(propValue != NULL);
+ if (strcmp((const char *)propValue, "skill") == 0) {
+ xmlChar *propSkill;
+ skill_t sk = NOSKILL;
+
+ modifiers[k].type = RMT_PROD_SKILL;
+ propSkill = xmlGetProp(node, BAD_CAST "skill");
+ if (propSkill) {
+ sk = findskill((const char *)propSkill);
+ xmlFree(propSkill);
+ }
+ modifiers[k].value.sa[0] = (short)sk;
+ modifiers[k].value.sa[1] = (short)xml_ivalue(node, "value", 0);
+ }
+ else if (strcmp((const char *)propValue, "material") == 0) {
+ modifiers[k].value = xml_fraction(node, "value");
+ modifiers[k].type = RMT_PROD_SAVE;
+ }
+ else {
+ if (strcmp((const char *)propValue, "require") == 0) {
+ modifiers[k].type = RMT_PROD_REQUIRE;
+ }
+ else if (strcmp((const char *)propValue, "save") == 0) {
+ modifiers[k].type = RMT_USE_SAVE;
+ modifiers[k].value = xml_fraction(node, "value");
+ }
+ else {
+ log_error("unknown type '%s' for resourcelimit-modifier", (const char *)propValue);
+ }
+ }
+ xmlFree(propValue);
+ }
+ return modifiers;
+ }
+ return NULL;
+}
+
static void
xml_readrequirements(xmlNodePtr * nodeTab, int nodeNr, requirement ** reqArray)
{
@@ -148,7 +215,7 @@ xml_readrequirements(xmlNodePtr * nodeTab, int nodeNr, requirement ** reqArray)
void
xml_readconstruction(xmlXPathContextPtr xpath, xmlNodeSetPtr nodeSet,
-construction ** consPtr)
+construction ** consPtr, construct_t type)
{
xmlNodePtr pushNode = xpath->node;
int k;
@@ -157,7 +224,6 @@ construction ** consPtr)
xmlChar *propValue;
construction *con;
xmlXPathObjectPtr req;
- int m;
skill_t sk = NOSKILL;
propValue = xmlGetProp(node, BAD_CAST "skill");
@@ -176,15 +242,18 @@ construction ** consPtr)
*consPtr = con = (construction *)calloc(sizeof(construction), 1);
consPtr = &con->improvement;
+ con->type = type;
con->skill = sk;
con->maxsize = xml_ivalue(node, "maxsize", -1);
con->minskill = xml_ivalue(node, "minskill", -1);
con->reqsize = xml_ivalue(node, "reqsize", 1);
- propValue = xmlGetProp(node, BAD_CAST "building");
- if (propValue != NULL) {
- con->btype = bt_get_or_create((const char *)propValue);
- xmlFree(propValue);
+ if (type == CONS_BUILDING) {
+ propValue = xmlGetProp(node, BAD_CAST "name");
+ if (propValue != NULL) {
+ con->name = strdup((const char *)propValue);
+ xmlFree(propValue);
+ }
}
/* read construction/requirement */
@@ -193,23 +262,6 @@ construction ** consPtr)
xml_readrequirements(req->nodesetval->nodeTab,
req->nodesetval->nodeNr, &con->materials);
xmlXPathFreeObject(req);
-
- /* read construction/modifier */
- xpath->node = node;
- req = xmlXPathEvalExpression(BAD_CAST "modifier", xpath);
- for (m = 0; m != req->nodesetval->nodeNr; ++m) {
- xmlNodePtr node = req->nodesetval->nodeTab[m];
-
- propValue = xmlGetProp(node, BAD_CAST "function");
- if (propValue != NULL) {
- pf_generic foo = get_function((const char *)propValue);
- a_add(&con->attribs, make_skillmod(NOSKILL, SMF_PRODUCTION,
- (skillmod_fun)foo, 1.0, 0));
- xmlFree(propValue);
- }
-
- }
- xmlXPathFreeObject(req);
}
xpath->node = pushNode;
}
@@ -221,11 +273,8 @@ parse_function(xmlNodePtr node, pf_generic * funPtr, xmlChar ** namePtr)
xmlChar *propValue = xmlGetProp(node, BAD_CAST "value");
assert(propValue != NULL);
fun = get_function((const char *)propValue);
- if (fun != NULL) {
- xmlFree(propValue);
-
- propValue = xmlGetProp(node, BAD_CAST "name");
- }
+ xmlFree(propValue);
+ propValue = xmlGetProp(node, BAD_CAST "name");
*namePtr = propValue;
*funPtr = fun;
return 0;
@@ -262,6 +311,7 @@ static int parse_buildings(xmlDocPtr doc)
btype->magresbonus = xml_ivalue(node, "magresbonus", btype->magresbonus);
btype->fumblebonus = xml_ivalue(node, "fumblebonus", btype->fumblebonus);
btype->auraregen = xml_fvalue(node, "auraregen", btype->auraregen);
+ btype->taxes = xml_ivalue(node, "taxes", btype->taxes);
if (xml_bvalue(node, "nodestroy", false))
btype->flags |= BTF_INDESTRUCTIBLE;
@@ -280,10 +330,16 @@ static int parse_buildings(xmlDocPtr doc)
if (xml_bvalue(node, "fort", false))
btype->flags |= BTF_FORTIFICATION;
+ /* reading eressea/buildings/building/modifier */
+ xpath->node = node;
+ result = xmlXPathEvalExpression(BAD_CAST "modifier", xpath);
+ btype->modifiers = xml_readmodifiers(result, node);
+ xmlXPathFreeObject(result);
+
/* reading eressea/buildings/building/construction */
xpath->node = node;
result = xmlXPathEvalExpression(BAD_CAST "construction", xpath);
- xml_readconstruction(xpath, result->nodesetval, &btype->construction);
+ xml_readconstruction(xpath, result->nodesetval, &btype->construction, CONS_BUILDING);
xmlXPathFreeObject(result);
/* reading eressea/buildings/building/function */
@@ -300,23 +356,7 @@ static int parse_buildings(xmlDocPtr doc)
continue;
}
assert(propValue != NULL);
- if (strcmp((const char *)propValue, "name") == 0) {
- btype->name =
- (const char *(*)(const struct building_type *,
- const struct building *, int))fun;
- }
- else if (strcmp((const char *)propValue, "init") == 0) {
- btype->init = (void(*)(struct building_type *))fun;
- }
- else if (strcmp((const char *)propValue, "age") == 0) {
- btype->age = (void(*)(struct building *))fun;
- }
- else if (strcmp((const char *)propValue, "taxes") == 0) {
- btype->taxes = (double(*)(const struct building *, int))fun;
- }
- else {
- log_error("unknown function type '%s' for building %s\n", (const char *)propValue, btype->_name);
- }
+ log_error("unknown function type '%s' for building %s\n", (const char *)propValue, btype->_name);
xmlFree(propValue);
}
xmlXPathFreeObject(result);
@@ -344,10 +384,6 @@ static int parse_buildings(xmlDocPtr doc)
mt->flags |= MTF_VARIABLE;
}
xmlXPathFreeObject(result);
-
- /* finally, initialize the new building type */
- if (btype->init)
- btype->init(btype);
}
}
xmlXPathFreeObject(buildings);
@@ -356,132 +392,6 @@ static int parse_buildings(xmlDocPtr doc)
return 0;
}
-static int parse_calendar(xmlDocPtr doc)
-{
- xmlXPathContextPtr xpath = xmlXPathNewContext(doc);
- xmlXPathObjectPtr xpathCalendars;
- xmlNodeSetPtr nsetCalendars;
-
- xpathCalendars = xmlXPathEvalExpression(BAD_CAST "/eressea/calendar", xpath);
- nsetCalendars = xpathCalendars->nodesetval;
- if (nsetCalendars != NULL && nsetCalendars->nodeNr != 0) {
- int c;
- for (c = 0; c != nsetCalendars->nodeNr; ++c) {
- xmlNodePtr calendar = nsetCalendars->nodeTab[c];
- xmlXPathObjectPtr xpathWeeks, xpathMonths, xpathSeasons;
- xmlNodeSetPtr nsetWeeks, nsetMonths, nsetSeasons;
- xmlChar *propValue = xmlGetProp(calendar, BAD_CAST "name");
- xmlChar *newyear = xmlGetProp(calendar, BAD_CAST "newyear");
- xmlChar *start;
-
- start = xmlGetProp(calendar, BAD_CAST "start");
- if (start && config_get("game.start") == NULL) {
- config_set("game.start", (const char *)start);
- xmlFree(start);
- }
- if (propValue) {
- free(agename);
- agename = strdup(mkname("calendar", (const char *)propValue));
- xmlFree(propValue);
- }
-
- xpath->node = calendar;
- xpathWeeks = xmlXPathEvalExpression(BAD_CAST "week", xpath);
- nsetWeeks = xpathWeeks->nodesetval;
- if (nsetWeeks != NULL && nsetWeeks->nodeNr) {
- int i;
-
- weeks_per_month = nsetWeeks->nodeNr;
- free(weeknames);
- free(weeknames2);
- weeknames = malloc(sizeof(char *) * weeks_per_month);
- weeknames2 = malloc(sizeof(char *) * weeks_per_month);
- for (i = 0; i != nsetWeeks->nodeNr; ++i) {
- xmlNodePtr week = nsetWeeks->nodeTab[i];
- xmlChar *propValue = xmlGetProp(week, BAD_CAST "name");
- if (propValue) {
- weeknames[i] = strdup(mkname("calendar", (const char *)propValue));
- weeknames2[i] = malloc(strlen(weeknames[i]) + 3);
- sprintf(weeknames2[i], "%s_d", weeknames[i]);
- xmlFree(propValue);
- }
- }
- }
- xmlXPathFreeObject(xpathWeeks);
-
- xpathSeasons = xmlXPathEvalExpression(BAD_CAST "season", xpath);
- nsetSeasons = xpathSeasons->nodesetval;
- if (nsetSeasons != NULL && nsetSeasons->nodeNr) {
- int i;
-
- seasons = nsetSeasons->nodeNr;
- assert(!seasonnames);
- seasonnames = malloc(sizeof(char *) * seasons);
-
- for (i = 0; i != nsetSeasons->nodeNr; ++i) {
- xmlNodePtr season = nsetSeasons->nodeTab[i];
- xmlChar *propValue = xmlGetProp(season, BAD_CAST "name");
- if (propValue) {
- seasonnames[i] =
- strdup(mkname("calendar", (const char *)propValue));
- xmlFree(propValue);
- }
- }
- }
-
- xpathMonths = xmlXPathEvalExpression(BAD_CAST "season/month", xpath);
- nsetMonths = xpathMonths->nodesetval;
- if (nsetMonths != NULL && nsetMonths->nodeNr) {
- int i;
-
- months_per_year = nsetMonths->nodeNr;
- free(monthnames);
- monthnames = malloc(sizeof(char *) * months_per_year);
- free(month_season);
- month_season = malloc(sizeof(int) * months_per_year);
- free(storms);
- storms = malloc(sizeof(int) * months_per_year);
-
- for (i = 0; i != nsetMonths->nodeNr; ++i) {
- xmlNodePtr month = nsetMonths->nodeTab[i];
- xmlChar *propValue = xmlGetProp(month, BAD_CAST "name");
-
- if (propValue) {
- if (newyear
- && strcmp((const char *)newyear, (const char *)propValue) == 0) {
- first_month = i;
- xmlFree(newyear);
- newyear = NULL;
- }
- monthnames[i] = strdup(mkname("calendar", (const char *)propValue));
- xmlFree(propValue);
- }
- if (nsetSeasons) {
- int j;
- for (j = 0; j != seasons; ++j) {
- xmlNodePtr season = month->parent;
- if (season == nsetSeasons->nodeTab[j]) {
- month_season[i] = j;
- break;
- }
- }
- assert(j != seasons);
- }
- storms[i] = xml_ivalue(nsetMonths->nodeTab[i], "storm", 0);
- }
- }
- xmlXPathFreeObject(xpathMonths);
- xmlXPathFreeObject(xpathSeasons);
- xmlFree(newyear);
- newyear = NULL;
- }
- }
- xmlXPathFreeObject(xpathCalendars);
- xmlXPathFreeContext(xpath);
-
- return 0;
-}
-
static int parse_ships(xmlDocPtr doc)
{
xmlXPathContextPtr xpath = xmlXPathNewContext(doc);
@@ -525,7 +435,7 @@ static int parse_ships(xmlDocPtr doc)
/* reading eressea/ships/ship/construction */
xpath->node = node;
result = xmlXPathEvalExpression(BAD_CAST "construction", xpath);
- xml_readconstruction(xpath, result->nodesetval, &st->construction);
+ xml_readconstruction(xpath, result->nodesetval, &st->construction, CONS_OTHER);
xmlXPathFreeObject(result);
for (child = node->children; child; child = child->next) {
@@ -757,6 +667,28 @@ static weapon_type *xml_readweapon(xmlXPathContextPtr xpath, item_type * itype)
return wtype;
}
+static int race_mask = 1;
+
+static void mask_races(xmlNodePtr node, const char *key, int *maskp) {
+ xmlChar *propValue = xmlGetProp(node, BAD_CAST key);
+ int mask = 0;
+ assert(maskp);
+ if (propValue) {
+ char * tok = strtok((char *)propValue, " ,");
+ while (tok) {
+ race * rc = rc_get_or_create(tok);
+ if (!rc->mask_item) {
+ rc->mask_item = race_mask;
+ race_mask = race_mask << 1;
+ }
+ mask |= rc->mask_item;
+ tok = strtok(NULL, " ,");
+ }
+ xmlFree(propValue);
+ }
+ *maskp = mask;
+}
+
static item_type *xml_readitem(xmlXPathContextPtr xpath, resource_type * rtype)
{
xmlNodePtr node = xpath->node;
@@ -767,6 +699,8 @@ static item_type *xml_readitem(xmlXPathContextPtr xpath, resource_type * rtype)
if (xml_bvalue(node, "cursed", false))
flags |= ITF_CURSED;
+ if (xml_bvalue(node, "use", false))
+ flags |= ITF_CANUSE;
if (xml_bvalue(node, "notlost", false))
flags |= ITF_NOTLOST;
if (xml_bvalue(node, "herb", false))
@@ -780,12 +714,14 @@ static item_type *xml_readitem(xmlXPathContextPtr xpath, resource_type * rtype)
itype = rtype->itype ? rtype->itype : it_get_or_create(rtype);
itype->weight = xml_ivalue(node, "weight", 0);
itype->capacity = xml_ivalue(node, "capacity", 0);
+ mask_races(node, "allow", &itype->mask_allow);
+ mask_races(node, "deny", &itype->mask_deny);
itype->flags |= flags;
/* reading item/construction */
xpath->node = node;
result = xmlXPathEvalExpression(BAD_CAST "construction", xpath);
- xml_readconstruction(xpath, result->nodesetval, &itype->construction);
+ xml_readconstruction(xpath, result->nodesetval, &itype->construction, CONS_ITEM);
xmlXPathFreeObject(result);
/* reading item/weapon */
@@ -803,6 +739,10 @@ static item_type *xml_readitem(xmlXPathContextPtr xpath, resource_type * rtype)
result = xmlXPathEvalExpression(BAD_CAST "potion", xpath);
assert(result->nodesetval->nodeNr <= 1);
if (result->nodesetval->nodeNr != 0) {
+ if ((itype->flags & ITF_CANUSE) == 0) {
+ log_error("potion %s has no use attribute", rtype->_name);
+ itype->flags |= ITF_CANUSE;
+ }
xpath->node = result->nodesetval->nodeTab[0];
rtype->ptype = xml_readpotion(xpath, itype);
}
@@ -843,28 +783,7 @@ static item_type *xml_readitem(xmlXPathContextPtr xpath, resource_type * rtype)
continue;
}
assert(propValue != NULL);
- if (strcmp((const char *)propValue, "give") == 0) {
- itype->give =
- (int(*)(struct unit *, struct unit *, const struct item_type *, int,
- struct order *))fun;
- }
- else if (strcmp((const char *)propValue, "use") == 0) {
- itype->use =
- (int(*)(struct unit *, const struct item_type *, int,
- struct order *))fun;
- }
- else if (strcmp((const char *)propValue, "canuse") == 0) {
- itype->canuse =
- (bool(*)(const struct unit *, const struct item_type *))fun;
- }
- else if (strcmp((const char *)propValue, "useonother") == 0) {
- itype->useonother =
- (int(*)(struct unit *, int, const struct item_type *, int,
- struct order *))fun;
- }
- else {
- log_error("unknown function type '%s' for item '%s'\n", (const char *)propValue, rtype->_name);
- }
+ log_error("unknown function type '%s' for item '%s'\n", (const char *)propValue, rtype->_name);
xmlFree(propValue);
}
itype->score = xml_ivalue(node, "score", 0);
@@ -874,44 +793,6 @@ static item_type *xml_readitem(xmlXPathContextPtr xpath, resource_type * rtype)
return itype;
}
-static int parse_rules(xmlDocPtr doc)
-{
- xmlXPathContextPtr xpath = xmlXPathNewContext(doc);
- xmlXPathObjectPtr functions;
- xmlNodeSetPtr nodes;
- int i;
-
- /* reading eressea/resources/resource */
- functions = xmlXPathEvalExpression(BAD_CAST "/eressea/rules/function", xpath);
- nodes = functions->nodesetval;
- for (i = 0; i != nodes->nodeNr; ++i) {
- xmlNodePtr node = nodes->nodeTab[i];
- xmlChar *propValue;
- pf_generic fun;
-
- parse_function(node, &fun, &propValue);
-
- if (fun == NULL) {
- log_error("unknown function for rule '%s' %s\n", (const char *)propValue);
- xmlFree(propValue);
- continue;
- }
- assert(propValue != NULL);
- if (strcmp((const char *)propValue, "wage") == 0) {
- global.functions.wage =
- (int(*)(const struct region *, const struct faction *,
- const struct race *, int))fun;
- }
- else {
- log_error("unknown function for rule '%s'\n", (const char *)propValue);
- }
- xmlFree(propValue);
- }
- xmlXPathFreeObject(functions);
- xmlXPathFreeContext(xpath);
- return 0;
-}
-
static int parse_resources(xmlDocPtr doc)
{
xmlXPathContextPtr xpath = xmlXPathNewContext(doc);
@@ -933,8 +814,6 @@ static int parse_resources(xmlDocPtr doc)
if (xml_bvalue(node, "pooled", true))
flags |= RTF_POOLED;
- if (xml_bvalue(node, "limited", false))
- flags |= RTF_LIMITED;
name = xmlGetProp(node, BAD_CAST "name");
if (!name) {
@@ -965,9 +844,6 @@ static int parse_resources(xmlDocPtr doc)
if (strcmp((const char *)propValue, "change") == 0) {
rtype->uchange = (rtype_uchange)fun;
}
- else if (strcmp((const char *)propValue, "get") == 0) {
- rtype->uget = (rtype_uget)fun;
- }
else if (strcmp((const char *)propValue, "name") == 0) {
rtype->name = (rtype_name)fun;
}
@@ -982,102 +858,12 @@ static int parse_resources(xmlDocPtr doc)
rmt_create(rtype);
}
- /* reading eressea/resources/resource/resourcelimit */
- xpath->node = node;
- result = xmlXPathEvalExpression(BAD_CAST "resourcelimit", xpath);
- assert(result->nodesetval->nodeNr <= 1);
- if (result->nodesetval->nodeNr != 0) {
- resource_limit *rdata = rtype->limit = calloc(1, sizeof(resource_limit));
- xmlNodePtr limit = result->nodesetval->nodeTab[0];
-
+ if (xml_bvalue(node, "limited", false)) {
rtype->flags |= RTF_LIMITED;
- xpath->node = limit;
- xmlXPathFreeObject(result);
-
- result = xmlXPathEvalExpression(BAD_CAST "modifier", xpath);
- if (result->nodesetval != NULL) {
- rdata->modifiers =
- calloc(result->nodesetval->nodeNr + 1, sizeof(resource_mod));
- for (k = 0; k != result->nodesetval->nodeNr; ++k) {
- xmlNodePtr node = result->nodesetval->nodeTab[k];
- building_type *btype = NULL;
- const race *rc = NULL;
-
- propValue = xmlGetProp(node, BAD_CAST "race");
- if (propValue != NULL) {
- rc = rc_find((const char *)propValue);
- if (rc == NULL)
- rc = rc_get_or_create((const char *)propValue);
- xmlFree(propValue);
- }
- rdata->modifiers[k].race = rc;
-
- propValue = xmlGetProp(node, BAD_CAST "building");
- if (propValue != NULL) {
- btype = bt_get_or_create((const char *)propValue);
- xmlFree(propValue);
- }
- rdata->modifiers[k].btype = btype;
-
- propValue = xmlGetProp(node, BAD_CAST "type");
- assert(propValue != NULL);
- if (strcmp((const char *)propValue, "skill") == 0) {
- rdata->modifiers[k].value.i = xml_ivalue(node, "value", 0);
- rdata->modifiers[k].flags = RMF_SKILL;
- }
- else if (strcmp((const char *)propValue, "material") == 0) {
- rdata->modifiers[k].value = xml_fraction(node, "value");
- rdata->modifiers[k].flags = RMF_SAVEMATERIAL;
- }
- else if (strcmp((const char *)propValue, "require") == 0) {
- xmlChar *propBldg = xmlGetProp(node, BAD_CAST "building");
- if (propBldg != NULL) {
- btype = bt_get_or_create((const char *)propBldg);
- rdata->modifiers[k].btype = btype;
- rdata->modifiers[k].flags = RMF_REQUIREDBUILDING;
- xmlFree(propBldg);
- }
- }
- else {
- log_error("unknown type '%s' for resourcelimit-modifier '%s'\n", (const char *)propValue, rtype->_name);
- }
- xmlFree(propValue);
- }
- }
- xmlXPathFreeObject(result);
-
- /* reading eressea/resources/resource/resourcelimit/function */
- result = xmlXPathEvalExpression(BAD_CAST "function", xpath);
- if (result->nodesetval != NULL) {
- for (k = 0; k != result->nodesetval->nodeNr; ++k) {
- xmlNodePtr node = result->nodesetval->nodeTab[k];
- pf_generic fun;
-
- propValue = xmlGetProp(node, BAD_CAST "value");
- assert(propValue != NULL);
- fun = get_function((const char *)propValue);
- if (fun == NULL) {
- log_error("unknown limit '%s' for resource %s\n", (const char *)propValue, rtype->_name);
- xmlFree(propValue);
- continue;
- }
- xmlFree(propValue);
-
- propValue = xmlGetProp(node, BAD_CAST "name");
- assert(propValue != NULL);
- if (strcmp((const char *)propValue, "produce") == 0) {
- rdata->produce = (rlimit_produce)fun;
- }
- else if (strcmp((const char *)propValue, "limit") == 0) {
- rdata->limit = (rlimit_limit)fun;
- }
- else {
- log_error("unknown limit '%s' for resource %s\n", (const char *)propValue, rtype->_name);
- }
- xmlFree(propValue);
- }
- }
}
+ xpath->node = node;
+ result = xmlXPathEvalExpression(BAD_CAST "modifier", xpath);
+ rtype->modifiers = xml_readmodifiers(result, node);
xmlXPathFreeObject(result);
/* reading eressea/resources/resource/resourcelimit/function */
xpath->node = node;
@@ -1383,12 +1169,8 @@ static int parse_spellbooks(xmlDocPtr doc)
static int parse_spells(xmlDocPtr doc)
{
- pf_generic cast = 0;
- pf_generic fumble = 0;
xmlXPathContextPtr xpath = xmlXPathNewContext(doc);
xmlXPathObjectPtr spells;
- char zText[32];
- strcpy(zText, "fumble_");
/* reading eressea/spells/spell */
spells = xmlXPathEvalExpression(BAD_CAST "/eressea/spells/spell", xpath);
@@ -1403,14 +1185,12 @@ static int parse_spells(xmlDocPtr doc)
int k;
spell_component *component;
spell *sp;
- unsigned int index;
static int modes[] = { 0, PRECOMBATSPELL, COMBATSPELL, POSTCOMBATSPELL };
/* spellname */
- index = xml_ivalue(node, "index", 0);
propValue = xmlGetProp(node, BAD_CAST "name");
assert(propValue != NULL);
- sp = create_spell((const char *)propValue, index);
+ sp = create_spell((const char *)propValue);
xmlFree(propValue);
if (!sp) {
continue;
@@ -1463,50 +1243,9 @@ static int parse_spells(xmlDocPtr doc)
sp->sptyp |= REGIONSPELL;
k = xml_ivalue(node, "combat", 0);
- if (k >= 0 && k <= 3)
+ if (k >= 0 && k <= 3) {
sp->sptyp |= modes[k];
-
- /* reading eressea/spells/spell/function */
-
- xpath->node = node;
- result = xmlXPathEvalExpression(BAD_CAST "function", xpath);
-
- if (result->nodesetval->nodeNr == 0) {
- cast = get_function(sp->sname);
- if (!cast) {
- log_error("no spell cast function registered for '%s'\n", sp->sname);
- }
- strlcpy(zText + 7, sp->sname, sizeof(zText) - 7);
- fumble = get_function(zText);
}
- else {
- for (k = 0; k != result->nodesetval->nodeNr; ++k) {
- xmlNodePtr node = result->nodesetval->nodeTab[k];
- pf_generic fun;
-
- parse_function(node, &fun, &propValue);
- assert(propValue != NULL);
- if (strcmp((const char *)propValue, "cast") == 0) {
- if (fun) {
- cast = fun;
- }
- else {
- log_error("unknown function name '%s' for spell '%s'\n", (const char *)propValue, sp->sname);
- }
- }
- else if (fun && strcmp((const char *)propValue, "fumble") == 0) {
- fumble = fun;
- }
- else {
- log_error("unknown function type '%s' for spell '%s'\n", (const char *)propValue, sp->sname);
- }
- xmlFree(propValue);
- }
- }
- sp->cast = (spell_f)cast;
- sp->fumble = (fumble_f)fumble;
- xmlXPathFreeObject(result);
-
/* reading eressea/spells/spell/resource */
xpath->node = node;
result = xmlXPathEvalExpression(BAD_CAST "resource", xpath);
@@ -1997,10 +1736,7 @@ static int parse_strings(xmlDocPtr doc)
void register_xmlreader(void)
{
- xml_register_callback(parse_rules);
-
xml_register_callback(parse_races);
- xml_register_callback(parse_calendar);
xml_register_callback(parse_resources);
xml_register_callback(parse_buildings); /* requires resources */
diff --git a/src/kernel/xmlreader.h b/src/kernel/xmlreader.h
index 5dfb643f1..290b785c3 100644
--- a/src/kernel/xmlreader.h
+++ b/src/kernel/xmlreader.h
@@ -12,6 +12,9 @@ without prior permission by the authors of Eressea.
#ifndef H_KRNL_XMLREADER_H
#define H_KRNL_XMLREADER_H
+
+struct spell;
+
#ifdef __cplusplus
extern "C" {
#endif
diff --git a/src/laws.c b/src/laws.c
index 1c71f1192..e16cbd583 100644
--- a/src/laws.c
+++ b/src/laws.c
@@ -45,6 +45,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
/* kernel includes */
#include
#include
+#include
#include
#include
#include
@@ -284,31 +285,6 @@ static double peasant_growth_factor(void)
return config_get_flt("rules.peasants.growth.factor", 0.0001F * PEASANTGROWTH);
}
-#ifdef SLOWLUCK
-int peasant_luck_effect(int peasants, int luck, int maxp, double variance) {
- int n, births = 0;
- double factor = peasant_growth_factor();
- for (n = peasants; n && luck; --n) {
- int chances = 0;
-
- if (luck > 0) {
- --luck;
- chances += PEASANTLUCK;
- }
-
- while (chances--) {
- if (rng_double() < factor) {
- /* Only raise with 75% chance if peasants have
- * reached 90% of maxpopulation */
- if (peasants / (float)maxp < 0.9 || chance(PEASANTFORCE)) {
- ++births;
- }
- }
- }
- }
- return births;
-}
-#else
static double peasant_luck_factor(void)
{
return config_get_flt("rules.peasants.peasantluck.factor", PEASANTLUCK);
@@ -331,9 +307,7 @@ int peasant_luck_effect(int peasants, int luck, int maxp, double variance)
return births;
}
-#endif
-
-static void peasants(region * r)
+static void peasants(region * r, int rule)
{
int peasants = rpeasants(r);
int money = rmoney(r);
@@ -341,7 +315,7 @@ static void peasants(region * r)
int n, satiated;
int dead = 0;
- if (peasants > 0 && config_get_int("rules.peasants.growth", 1)) {
+ if (peasants > 0 && rule > 0) {
int luck = 0;
double fraction = peasants * peasant_growth_factor();
int births = RAND_ROUND(fraction);
@@ -812,6 +786,8 @@ void demographics(void)
static int last_weeks_season = -1;
static int current_season = -1;
int plant_rules = config_get_int("rules.grow.formula", 2);
+ int horse_rules = config_get_int("rules.horses.growth", 1);
+ int peasant_rules = config_get_int("rules.peasants.growth", 1);
const struct building_type *bt_harbour = bt_find("harbour");
if (current_season < 0) {
@@ -843,7 +819,8 @@ void demographics(void)
* und gewandert sind */
calculate_emigration(r);
- peasants(r);
+ peasants(r, peasant_rules);
+
if (r->age > 20) {
double mwp = MAX(region_maxworkers(r), 1);
double prob =
@@ -854,7 +831,9 @@ void demographics(void)
plagues(r);
}
}
- horses(r);
+ if (horse_rules > 0) {
+ horses(r);
+ }
if (plant_rules == 2) { /* E2 */
growing_trees(r, current_season, last_weeks_season);
growing_herbs(r, current_season, last_weeks_season);
@@ -1274,8 +1253,8 @@ static void remove_idle_players(void)
}
else if (turn != f->lastorders) {
char info[256];
- sprintf(info, "%d Einheiten, %d Personen, %d Silber",
- f->no_units, f->num_total, f->money);
+ sprintf(info, "%d Einheiten, %d Personen",
+ f->num_units, f->num_people);
}
fp = &f->next;
}
@@ -1605,10 +1584,14 @@ int display_cmd(unit * u, struct order *ord)
free(*s);
if (s2) {
- *s = strdup(s2);
- if (strlen(s2) >= DISPLAYSIZE) {
- (*s)[DISPLAYSIZE] = 0;
+ char * str = strdup(s2);
+ if (unicode_utf8_trim(str) != 0) {
+ log_info("trimming info: %s", s2);
}
+ if (strlen(str) >= DISPLAYSIZE) {
+ str[DISPLAYSIZE-1] = 0;
+ }
+ *s = str;
}
else {
*s = 0;
@@ -1646,7 +1629,9 @@ 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));
- unicode_utf8_trim(name);
+ if (unicode_utf8_trim(name) != 0) {
+ log_info("trimming name: %s", s2);
+ }
free(*s);
*s = strdup(name);
@@ -2405,6 +2390,7 @@ static void display_race(unit * u, const race * rc)
static void reshow_other(unit * u, struct order *ord, const char *s) {
int err = 21;
+ bool found = false;
if (s) {
const spell *sp = 0;
@@ -2441,7 +2427,7 @@ static void reshow_other(unit * u, struct order *ord, const char *s) {
else {
display_item(u, itype);
}
- return;
+ found = true;
}
if (sp) {
@@ -2452,15 +2438,16 @@ static void reshow_other(unit * u, struct order *ord, const char *s) {
if (a != NULL) {
a_remove(&u->faction->attribs, a);
}
- return;
+ found = true;
}
if (rc && u_race(u) == rc) {
display_race(u, rc);
- return;
+ found = true;
}
}
- 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)
@@ -2514,7 +2501,7 @@ int promotion_cmd(unit * u, struct order *ord)
u_race(u)));
return 0;
}
- people = count_all(u->faction) * u->number;
+ people = u->faction->num_people * u->number;
money = get_pooled(u, rsilver, GET_ALL, people);
if (people > money) {
@@ -2899,10 +2886,6 @@ static building *age_building(building * b)
a_age(&b->attribs, b);
handle_event(b->attribs, "timer", b);
- if (b->type->age) {
- b->type->age(b);
- }
-
return b;
}
@@ -3015,8 +2998,7 @@ static int maxunits(const faction * f)
int checkunitnumber(const faction * f, int add)
{
int alimit, flimit;
- int flags = COUNT_DEFAULT | COUNT_MIGRANTS | COUNT_UNITS;
- int fno = count_faction(f, flags) + add;
+ int fno = f->num_units + add;
flimit = rule_faction_limit();
if (flimit && fno > flimit) {
return 2;
@@ -3024,22 +3006,10 @@ int checkunitnumber(const faction * f, int add)
alimit = rule_alliance_limit();
if (alimit) {
- /* if unitsperalliance is true, maxunits returns the
- number of units allowed in an alliance */
- faction *f2;
- int unitsinalliance = fno;
- if (unitsinalliance > alimit) {
+ int unitsinalliance = alliance_size(f->alliance);
+ if (unitsinalliance + add > alimit) {
return 1;
}
-
- for (f2 = factions; f2; f2 = f2->next) {
- if (f != f2 && f->alliance == f2->alliance) {
- unitsinalliance += count_faction(f2, flags);
- if (unitsinalliance > alimit) {
- return 1;
- }
- }
- }
}
return 0;
@@ -3240,11 +3210,6 @@ void update_long_order(unit * u)
static int use_item(unit * u, const item_type * itype, int amount, struct order *ord)
{
int i;
- int target = -1;
-
- if (itype->useonother) {
- target = read_unitid(u->faction, u->region);
- }
i = get_pooled(u, itype->rtype, GET_DEFAULT, amount);
if (amount > i) {
@@ -3255,19 +3220,14 @@ static int use_item(unit * u, const item_type * itype, int amount, struct order
return ENOITEM;
}
- if (target == -1) {
- if (itype->use) {
- int result = itype->use(u, itype, amount, ord);
- if (result > 0) {
- use_pooled(u, itype->rtype, GET_DEFAULT, result);
- }
- return result;
+ if (itype->flags & ITF_CANUSE) {
+ int result = callbacks.use_item(u, itype, amount, ord);
+ if (result > 0) {
+ use_pooled(u, itype->rtype, GET_DEFAULT, result);
}
- return EUNUSABLE;
- }
- else {
- return itype->useonother(u, target, itype, amount, ord);
+ return result;
}
+ return EUNUSABLE;
}
void monthly_healing(void)
@@ -4226,6 +4186,7 @@ static void reset_game(void)
void turn_begin(void)
{
+ assert(turn >= 0);
++turn;
reset_game();
}
@@ -4290,12 +4251,18 @@ void update_subscriptions(void)
fclose(F);
}
-bool
-cansee(const faction * f, const region * r, const unit * u, int modifier)
-/* r kann != u->region sein, wenn es um Durchreisen geht,
+/** determine if unit can be seen by faction
+ * @param f -- the observiong faction
+ * @param u -- the unit that is observed
+ * @param r -- the region that u is obesrved in (see below)
+ * @param m -- terrain modifier to stealth
+ *
+ * r kann != u->region sein, wenn es um Durchreisen geht,
* oder Zauber (sp_generous, sp_fetchastral).
* Es muss auch niemand aus f in der region sein, wenn sie vom Turm
* erblickt wird */
+bool
+cansee(const faction * f, const region * r, const unit * u, int modifier)
{
int stealth, rings;
unit *u2 = r->units;
diff --git a/src/laws.h b/src/laws.h
index 090d2b978..7f1385483 100755
--- a/src/laws.h
+++ b/src/laws.h
@@ -58,6 +58,7 @@ extern "C" {
void turn_process(void);
void turn_end(void);
+ int checkunitnumber(const struct faction * f, int add);
void new_units(void);
void defaultorders(void);
void quit(void);
diff --git a/src/laws.test.c b/src/laws.test.c
index 937754988..4d6adbfe9 100644
--- a/src/laws.test.c
+++ b/src/laws.test.c
@@ -5,6 +5,7 @@
#include "monsters.h"
#include
+#include
#include
#include
#include
@@ -427,7 +428,51 @@ static void test_unit_limit(CuTest * tc)
test_cleanup();
}
-extern int checkunitnumber(const faction * f, int add);
+static void test_limit_new_units(CuTest * tc)
+{
+ faction *f;
+ unit *u;
+ alliance *al;
+
+ test_setup();
+ al = makealliance(1, "Hodor");
+ f = test_create_faction(NULL);
+ u = test_create_unit(f, test_create_region(0, 0, NULL));
+ CuAssertIntEquals(tc, 1, f->num_units);
+ CuAssertIntEquals(tc, 1, f->num_people);
+ scale_number(u, 10);
+ CuAssertIntEquals(tc, 10, f->num_people);
+ config_set("rules.limit.faction", "2");
+
+ u->orders = create_order(K_MAKETEMP, f->locale, "1");
+ new_units();
+ CuAssertPtrNotNull(tc, u->next);
+ CuAssertIntEquals(tc, 2, f->num_units);
+
+ new_units();
+ CuAssertIntEquals(tc, 2, f->num_units);
+ CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "too_many_units_in_faction"));
+
+ setalliance(f, al);
+
+ config_set("rules.limit.faction", "3");
+ config_set("rules.limit.alliance", "2");
+
+ new_units();
+ CuAssertIntEquals(tc, 2, f->num_units);
+ CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "too_many_units_in_alliance"));
+
+ config_set("rules.limit.alliance", "3");
+ u = test_create_unit(test_create_faction(NULL), u->region);
+ setalliance(u->faction, al);
+
+ new_units();
+ CuAssertIntEquals(tc, 2, f->num_units);
+ CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "too_many_units_in_alliance"));
+
+ test_cleanup();
+}
+
static void test_cannot_create_unit_above_limit(CuTest * tc)
{
faction *f;
@@ -480,10 +525,6 @@ struct pay_fixture {
unit *u2;
};
-static double level_taxes(const building * b, int level) {
- return b->size * level * 2.0;
-}
-
static void setup_pay_cmd(struct pay_fixture *fix) {
faction *f;
region *r;
@@ -495,7 +536,7 @@ static void setup_pay_cmd(struct pay_fixture *fix) {
r = findregion(0, 0);
assert(r && f);
btcastle = test_create_buildingtype("castle");
- btcastle->taxes = level_taxes;
+ btcastle->taxes = 100;
b = test_create_building(r, btcastle);
assert(b);
fix->u1 = test_create_unit(f, r);
@@ -1322,42 +1363,6 @@ static void test_show_without_item(CuTest *tc)
test_cleanup();
}
-static void test_show_elf(CuTest *tc) {
- order *ord;
- race * rc;
- unit *u;
- struct locale *loc;
- message * msg;
-
- test_setup();
-
- mt_register(mt_new_va("msg_event", "string:string", 0));
- rc = test_create_race("elf");
- test_create_itemtype("elvenhorse");
-
- loc = test_create_locale();
- locale_setstring(loc, "elvenhorse", "Elfenpferd");
- locale_setstring(loc, "elvenhorse_p", "Elfenpferde");
- locale_setstring(loc, "race::elf_p", "Elfen");
- locale_setstring(loc, "race::elf", "Elf");
- init_locale(loc);
-
- 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->faction->locale = loc;
- ord = create_order(K_RESHOW, loc, "Elf");
- reshow_cmd(u, ord);
- CuAssertTrue(tc, test_find_messagetype(u->faction->msgs, "error36") == NULL);
- msg = test_find_messagetype(u->faction->msgs, "msg_event");
- CuAssertPtrNotNull(tc, msg);
- CuAssertTrue(tc, memcmp("Elf:", msg->parameters[0].v, 4) == 0);
- test_clear_messages(u->faction);
- free_order(ord);
- test_cleanup();
-}
-
static void test_show_race(CuTest *tc) {
order *ord;
race * rc;
@@ -1399,15 +1404,52 @@ static void test_show_race(CuTest *tc) {
test_cleanup();
}
-static int low_wage(const region * r, const faction * f, const race * rc, int in_turn) {
- return 1;
+static void test_show_both(CuTest *tc) {
+ order *ord;
+ race * rc;
+ unit *u;
+ 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));
+ rc = test_create_race("elf");
+ test_create_itemtype("elvenhorse");
+
+ loc = get_or_create_locale("de");
+ locale_setstring(loc, "elvenhorse", "Elfenpferd");
+ locale_setstring(loc, "elvenhorse_p", "Elfenpferde");
+ locale_setstring(loc, "iteminfo::elvenhorse", "Hiyaa!");
+ locale_setstring(loc, "race::elf_p", "Elfen");
+ locale_setstring(loc, "race::elf", "Elf");
+ init_locale(loc);
+
+ 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->faction->locale = loc;
+ i_change(&u->items, finditemtype("elfenpferd", loc), 1);
+ ord = create_order(K_RESHOW, loc, "Elf");
+ reshow_cmd(u, ord);
+ CuAssertTrue(tc, test_find_messagetype(u->faction->msgs, "error36") == NULL);
+ msg = test_find_messagetype(u->faction->msgs, "msg_event");
+ CuAssertPtrNotNull(tc, msg);
+ CuAssertTrue(tc, memcmp("Elf:", msg->parameters[0].v, 4) == 0);
+ msg = test_find_messagetype(u->faction->msgs, "displayitem");
+ CuAssertPtrNotNull(tc, msg);
+ CuAssertTrue(tc, memcmp("Hiyaa!", msg->parameters[2].v, 4) == 0);
+ test_clear_messages(u->faction);
+ free_order(ord);
+ test_cleanup();
}
static void test_immigration(CuTest * tc)
{
region *r;
double inject[] = { 1 };
- int (*old_wage)(const region*, const faction*, const race*, int) = global.functions.wage;
test_setup();
r = test_create_region(0, 0, 0);
@@ -1427,10 +1469,9 @@ static void test_immigration(CuTest * tc)
random_source_inject_array(inject, 2);
- global.functions.wage = low_wage;
+ config_set("rules.wage.function", "0");
immigration();
CuAssertIntEquals(tc, 2, rpeasants(r));
- global.functions.wage = old_wage;
test_cleanup();
}
@@ -1535,6 +1576,7 @@ CuSuite *get_laws_suite(void)
SUITE_ADD_TEST(suite, test_fishing_does_not_give_goblins_money);
SUITE_ADD_TEST(suite, test_fishing_gets_reset);
SUITE_ADD_TEST(suite, test_unit_limit);
+ SUITE_ADD_TEST(suite, test_limit_new_units);
SUITE_ADD_TEST(suite, test_update_guards);
SUITE_ADD_TEST(suite, test_newbie_cannot_guard);
SUITE_ADD_TEST(suite, test_unarmed_cannot_guard);
@@ -1571,8 +1613,8 @@ CuSuite *get_laws_suite(void)
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_elf);
SUITE_ADD_TEST(suite, test_show_race);
+ SUITE_ADD_TEST(suite, test_show_both);
SUITE_ADD_TEST(suite, test_immigration);
SUITE_ADD_TEST(suite, test_demon_hunger);
SUITE_ADD_TEST(suite, test_armedmen);
diff --git a/src/magic.c b/src/magic.c
index de1336d66..81a797e1c 100644
--- a/src/magic.c
+++ b/src/magic.c
@@ -23,10 +23,12 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include "skill.h"
#include "study.h"
+#include "helpers.h"
#include "laws.h"
#include
#include
+#include
#include
#include
#include
@@ -231,26 +233,6 @@ bool FactionSpells(void)
return rule != 0;
}
-void read_spells(struct selist **slistp, magic_t mtype,
- struct storage *store)
-{
- for (;;) {
- spell *sp;
- char spname[64];
-
- READ_TOK(store, spname, sizeof(spname));
- if (strcmp(spname, "end") == 0)
- break;
- sp = find_spell(spname);
- if (!sp) {
- log_error("read_spells: could not find spell '%s' in school '%s'\n", spname, magic_school[mtype]);
- }
- if (sp) {
- add_spell(slistp, sp);
- }
- }
-}
-
int get_spell_level_mage(const spell * sp, void * cbdata)
{
sc_mage *mage = (sc_mage *)cbdata;
@@ -305,18 +287,6 @@ static int read_mage(attrib * a, void *owner, struct gamedata *data)
return AT_READ_OK;
}
-void write_spells(struct selist *slist, struct storage *store)
-{
- selist *ql;
- int qi;
-
- for (ql = slist, qi = 0; ql; selist_advance(&ql, &qi, 1)) {
- spell *sp = (spell *)selist_get(ql, qi);
- WRITE_TOK(store, sp->sname);
- }
- WRITE_TOK(store, "end");
-}
-
static void
write_mage(const attrib * a, const void *owner, struct storage *store)
{
@@ -371,23 +341,16 @@ sc_mage *get_mage(const unit * u)
static int read_seenspell(attrib * a, void *owner, struct gamedata *data)
{
storage *store = data->store;
- int i;
spell *sp = 0;
char token[32];
READ_TOK(store, token, sizeof(token));
- i = atoip(token);
- if (i != 0) {
- sp = find_spellbyid((unsigned int)i);
+ if (data->version < UNIQUE_SPELLS_VERSION) {
+ READ_INT(store, 0); /* ignore mtype */
}
- else {
- if (data->version < UNIQUE_SPELLS_VERSION) {
- READ_INT(store, 0); /* ignore mtype */
- }
- sp = find_spell(token);
- if (!sp) {
- log_warning("read_seenspell: could not find spell '%s'\n", token);
- }
+ sp = find_spell(token);
+ if (!sp) {
+ log_warning("read_seenspell: could not find spell '%s'\n", token);
}
if (!sp) {
return AT_READ_FAIL;
@@ -930,9 +893,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? */
- if (!sp || sp->id == 0) {
- return false;
- }
+ assert(sp);
/* steht der Spruch in der Spruchliste? */
return u_hasspell(u, sp) != 0;
}
@@ -1146,7 +1107,7 @@ variant magic_resistance(unit * target)
const plane *pl = rplane(target->region);
if (rc == get_race(RC_HIRNTOETER) && !pl) {
- prob.sa[1] *= 2;
+ prob = frac_mul(prob, frac_make(1, 2));
}
assert(target->number > 0);
/* Magier haben einen Resistenzbonus vom Magietalent * 5% */
@@ -1402,14 +1363,16 @@ static void do_fumble(castorder * co)
double effect;
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) {
case 0:
/* wenn vorhanden spezieller Patzer, ansonsten nix */
- if (sp->fumble) {
- sp->fumble(co);
+ fun = get_fumble(sp->sname);
+ if (fun) {
+ fun(co);
}
else {
fumble_default(co);
@@ -1463,7 +1426,7 @@ static void do_fumble(castorder * co)
case 5:
case 6:
/* Spruch gelingt, aber alle Magiepunkte weg */
- co->level = sp->cast(co);
+ co->level = cast_spell(co);
set_spellpoints(u, 0);
ADDMSG(&u->faction->msgs, msg_message("patzer4", "unit region spell",
u, r, sp));
@@ -1474,7 +1437,7 @@ static void do_fumble(castorder * co)
case 9:
default:
/* Spruch gelingt, alle nachfolgenden Sprüche werden 2^4 so teuer */
- co->level = sp->cast(co);
+ co->level = cast_spell(co);
ADDMSG(&u->faction->msgs, msg_message("patzer5", "unit region spell",
u, r, sp));
countspells(u, 3);
@@ -2930,7 +2893,7 @@ void magic(void)
fumbled = true;
}
else {
- co->level = sp->cast(co);
+ co->level = cast_spell(co);
if (co->level <= 0) {
/* Kosten nur für real benötige Stufe berechnen */
continue;
@@ -3033,6 +2996,30 @@ spell *unit_getspell(struct unit *u, const char *name, const struct locale * lan
return 0;
}
+int cast_spell(struct castorder *co)
+{
+ const char *fname = co->sp->sname;
+ const char *hashpos = strchr(fname, '#');
+ char fbuf[64];
+ spell_f fun;
+
+ const spell *sp = co->sp;
+ if (hashpos != NULL) {
+ ptrdiff_t len = hashpos - fname;
+ assert(len < (ptrdiff_t) sizeof(fbuf));
+ memcpy(fbuf, fname, len);
+ fbuf[len] = '\0';
+ fname = fbuf;
+ }
+
+ fun = get_spellcast(sp->sname);
+ if (!fun) {
+ log_warning("no spell function for %s, try callback", sp->sname);
+ return callbacks.cast_spell(co, fname);
+ }
+ return fun(co);
+}
+
static critbit_tree cb_spellbooks;
spellbook * get_spellbook(const char * name)
diff --git a/src/magic.h b/src/magic.h
index 37fe33eae..6c905ea68 100644
--- a/src/magic.h
+++ b/src/magic.h
@@ -244,10 +244,6 @@ extern "C" {
/* prft, ob der Spruch in der Spruchliste der Einheit steht. */
void pick_random_spells(struct faction *f, int level, struct spellbook * book, int num_spells);
void show_new_spells(struct faction * f, int level, const struct spellbook *book);
- void updatespelllist(struct unit *u);
- /* fgt alle Zauber des Magiegebietes der Einheit, deren Stufe kleiner
- * als das aktuelle Magietalent ist, in die Spruchliste der Einheit
- * ein */
bool knowsspell(const struct region *r, const struct unit *u,
const struct spell * sp);
/* prft, ob die Einheit diesen Spruch gerade beherrscht, dh
@@ -290,6 +286,7 @@ extern "C" {
/* Hnge c-order co an die letze c-order von cll an */
void free_castorders(struct castorder *co);
/* Speicher wieder freigeben */
+ int cast_spell(struct castorder *co);
/* Prfroutinen fr Zaubern */
int countspells(struct unit *u, int step);
@@ -349,10 +346,6 @@ extern "C" {
struct order *ord, const struct spllprm *spobj);
bool FactionSpells(void);
- void write_spells(struct selist *slist, struct storage *store);
- void read_spells(struct selist **slistp, magic_t mtype,
- struct storage *store);
-
struct spellbook * get_spellbook(const char * name);
void free_spellbooks(void);
void free_spellbook(struct spellbook *sb);
diff --git a/src/magic.test.c b/src/magic.test.c
index a3a199e42..a1b55b45d 100644
--- a/src/magic.test.c
+++ b/src/magic.test.c
@@ -4,7 +4,7 @@
#include "teleport.h"
#include "give.h"
-#include
+#include
#include
#include
#include
@@ -14,13 +14,16 @@
#include
#include
#include
-#include
+
+#include
#include
#include
+#include
#include
#include
+#include
void test_updatespells(CuTest * tc)
{
@@ -32,7 +35,7 @@ void test_updatespells(CuTest * tc)
test_create_race("human");
f = test_create_faction(0);
- sp = create_spell("testspell", 0);
+ sp = create_spell("testspell");
CuAssertPtrNotNull(tc, sp);
book = create_spellbook("spells");
@@ -65,7 +68,7 @@ void test_spellbooks(CuTest * tc)
CuAssertStrEquals(tc, "herp", herp->name);
CuAssertStrEquals(tc, "derp", derp->name);
- sp = create_spell(sname, 0);
+ sp = create_spell(sname);
spellbook_add(herp, sp, 1);
CuAssertPtrNotNull(tc, sp);
entry = spellbook_get(herp, sp);
@@ -168,7 +171,7 @@ void test_getspell_unit(CuTest * tc)
set_level(u, SK_MAGIC, 1);
lang = test_create_locale();
- sp = create_spell("testspell", 0);
+ sp = create_spell("testspell");
locale_setstring(lang, mkname("spell", sp->sname), "Herp-a-derp");
CuAssertPtrEquals(tc, 0, unit_getspell(u, "Herp-a-derp", lang));
@@ -197,7 +200,7 @@ void test_getspell_faction(CuTest * tc)
set_level(u, SK_MAGIC, 1);
lang = test_create_locale();
- sp = create_spell("testspell", 0);
+ sp = create_spell("testspell");
locale_setstring(lang, mkname("spell", sp->sname), "Herp-a-derp");
CuAssertPtrEquals(tc, 0, unit_getspell(u, "Herp-a-derp", lang));
@@ -227,7 +230,7 @@ void test_getspell_school(CuTest * tc)
set_level(u, SK_MAGIC, 1);
lang = test_create_locale();
- sp = create_spell("testspell", 0);
+ sp = create_spell("testspell");
locale_setstring(lang, mkname("spell", sp->sname), "Herp-a-derp");
CuAssertPtrEquals(tc, 0, unit_getspell(u, "Herp-a-derp", lang));
@@ -254,7 +257,7 @@ void test_set_pre_combatspell(CuTest * tc)
u = test_create_unit(f, r);
enable_skill(SK_MAGIC, true);
set_level(u, SK_MAGIC, 1);
- sp = create_spell("testspell", 0);
+ sp = create_spell("testspell");
sp->sptyp |= PRECOMBATSPELL;
unit_add_spell(u, 0, sp, 1);
@@ -286,7 +289,7 @@ void test_set_main_combatspell(CuTest * tc)
u = test_create_unit(f, r);
enable_skill(SK_MAGIC, true);
set_level(u, SK_MAGIC, 1);
- sp = create_spell("testspell", 0);
+ sp = create_spell("testspell");
sp->sptyp |= COMBATSPELL;
unit_add_spell(u, 0, sp, 1);
@@ -318,7 +321,7 @@ void test_set_post_combatspell(CuTest * tc)
u = test_create_unit(f, r);
enable_skill(SK_MAGIC, true);
set_level(u, SK_MAGIC, 1);
- sp = create_spell("testspell", 0);
+ sp = create_spell("testspell");
sp->sptyp |= POSTCOMBATSPELL;
unit_add_spell(u, 0, sp, 1);
@@ -348,7 +351,7 @@ void test_hasspell(CuTest * tc)
f->magiegebiet = M_TYBIED;
u = test_create_unit(f, r);
enable_skill(SK_MAGIC, true);
- sp = create_spell("testspell", 0);
+ sp = create_spell("testspell");
sp->sptyp |= POSTCOMBATSPELL;
unit_add_spell(u, 0, sp, 2);
@@ -377,8 +380,8 @@ void test_multi_cast(CuTest *tc) {
struct locale * lang;
test_setup();
- sp = create_spell("fireball", 0);
- sp->cast = cast_fireball;
+ add_spellcast("fireball", cast_fireball);
+ sp = create_spell("fireball");
CuAssertPtrEquals(tc, sp, find_spell("fireball"));
lang = test_create_locale();
@@ -460,6 +463,27 @@ static void test_familiar_mage(CuTest *tc) {
test_cleanup();
}
+static void test_illusioncastle(CuTest *tc)
+{
+ building *b;
+ building_type *btype, *bt_icastle;
+ const attrib *a;
+ test_setup();
+ btype = test_create_buildingtype("castle");
+ bt_icastle = test_create_buildingtype("illusioncastle");
+ b = test_create_building(test_create_region(0, 0, NULL), bt_icastle);
+ b->size = 1;
+ make_icastle(b, btype, 10);
+ a = a_find(b->attribs, &at_icastle);
+ CuAssertPtrNotNull(tc, a);
+ 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");
+ CuAssertStrEquals(tc, "site", buildingtype(btype, b, b->size));
+ test_cleanup();
+}
+
CuSuite *get_magic_suite(void)
{
CuSuite *suite = CuSuiteNew();
@@ -477,6 +501,7 @@ CuSuite *get_magic_suite(void)
SUITE_ADD_TEST(suite, test_hasspell);
SUITE_ADD_TEST(suite, test_magic_resistance);
SUITE_ADD_TEST(suite, test_max_spellpoints);
+ SUITE_ADD_TEST(suite, test_illusioncastle);
DISABLE_TEST(suite, test_familiar_mage);
return suite;
}
diff --git a/src/main.c b/src/main.c
index dd65ec9e1..eedb25cf1 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,5 +1,5 @@
/*
-Copyright (c) 1998-2015, Enno Rehling
+Copyright (c) 1998-2017, Enno Rehling
Katja Zedel
@@ -45,33 +45,53 @@ static const char *inifile = "eressea.ini";
static int memdebug = 0;
static int verbosity = 1;
-static void load_inifile(dictionary * d)
+static void load_inifile(void)
{
- const char *reportdir = reportpath();
- const char *datadir = datapath();
- const char *basedir = basepath();
const char *str;
- assert(d);
-
- str = iniparser_getstring(d, "game:base", basedir);
- if (str != basedir) {
+ str = config_get("game.base");
+ if (str) {
set_basepath(str);
}
- str = iniparser_getstring(d, "game:report", reportdir);
- if (str != reportdir) {
+ str = config_get("game.report");
+ if (str) {
set_reportpath(str);
}
- str = iniparser_getstring(d, "game:data", datadir);
- if (str != datadir) {
+ str = config_get("game.data");
+ if (str) {
set_datapath(str);
}
- lomem = iniparser_getint(d, "game:lomem", lomem) ? 1 : 0;
-
- verbosity = iniparser_getint(d, "game:verbose", 2);
+ 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
+ /* only one value in the [editor] section */
+ force_color = config_get_int("editor.color", force_color);
+ gm_codepage = config_get_int("editor.codepage", gm_codepage);
+#endif
}
+static const char * valid_keys[] = {
+ "game.id",
+ "game.name",
+ "game.start",
+ "game.locale",
+ "game.verbose",
+ "game.report",
+ "game.lomem",
+ "game.memcheck",
+ "game.email",
+ "game.mailcmd",
+ "game.era",
+ "game.sender",
+ "editor.color",
+ "editor.codepage",
+ "editor.population.",
+ "lua.",
+ NULL
+};
+
static dictionary *parse_config(const char *filename)
{
char path[MAX_PATH];
@@ -87,15 +107,8 @@ static dictionary *parse_config(const char *filename)
d = iniparser_load(filename);
}
if (d) {
- load_inifile(d);
- config_set_from(d);
-
- memdebug = iniparser_getint(d, "game:memcheck", memdebug);
-#ifdef USE_CURSES
- /* only one value in the [editor] section */
- force_color = iniparser_getint(d, "editor:color", force_color);
- gm_codepage = iniparser_getint(d, "editor:codepage", gm_codepage);
-#endif
+ config_set_from(d, valid_keys);
+ load_inifile();
}
str = config_get("game.locales");
make_locales(str ? str : "de,en");
@@ -152,7 +165,7 @@ static int verbosity_to_flags(int verbosity) {
return flags;
}
-static int parse_args(int argc, char **argv, int *exitcode)
+static int parse_args(int argc, char **argv)
{
int i;
int log_stderr = LOG_CPERROR;
@@ -165,10 +178,10 @@ static int parse_args(int argc, char **argv, int *exitcode)
}
else if (argi[1] == '-') { /* long format */
if (strcmp(argi + 2, "version") == 0) {
- printf("\n%s PBEM host\n"
- "Copyright (C) 1996-2005 C. Schlittchen, K. Zedel, E. Rehling, H. Peters.\n\n"
- "Compilation: " __DATE__ " at " __TIME__ "\nVersion: %s\n\n",
- game_name(), eressea_version());
+ printf("Eressea version %s, "
+ "Copyright (C) 2017 Enno Rehling et al.\n",
+ eressea_version());
+ return 1;
#ifdef USE_CURSES
}
else if (strcmp(argi + 2, "color") == 0) {
@@ -216,7 +229,6 @@ static int parse_args(int argc, char **argv, int *exitcode)
usage(argv[0], NULL);
return 1;
default:
- *exitcode = -1;
usage(argv[0], argi);
return 1;
}
@@ -287,8 +299,10 @@ int main(int argc, char **argv)
dictionary *d = 0;
setup_signal_handler();
/* parse arguments again, to override ini file */
- parse_args(argc, argv, &err);
-
+ err = parse_args(argc, argv);
+ if (err!=0) {
+ return (err>0) ? 0 : err;
+ }
d = parse_config(inifile);
if (!d) {
log_error("could not open ini configuration %s\n", inifile);
diff --git a/src/market.test.c b/src/market.test.c
index a631dbcb7..2beeaea6b 100644
--- a/src/market.test.c
+++ b/src/market.test.c
@@ -43,9 +43,7 @@ static void test_market_curse(CuTest * tc)
config_set("rules.region_owners", "1");
- btype = (building_type *)calloc(1, sizeof(building_type));
- btype->_name = strdup("market");
- bt_register(btype);
+ btype = bt_get_or_create("market");
terrain = get_terrain("plain");
diff --git a/src/modules/CMakeLists.txt b/src/modules/CMakeLists.txt
index 633c486f5..82dee9ec4 100644
--- a/src/modules/CMakeLists.txt
+++ b/src/modules/CMakeLists.txt
@@ -1,6 +1,5 @@
PROJECT(modules C)
SET(_FILES
-arena.c
autoseed.c
gmcmd.c
museum.c
diff --git a/src/modules/arena.c b/src/modules/arena.c
deleted file mode 100644
index aada12234..000000000
--- a/src/modules/arena.c
+++ /dev/null
@@ -1,255 +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