diff --git a/.editorconfig b/.editorconfig index cd3315bd8..fafe79d54 100644 --- a/.editorconfig +++ b/.editorconfig @@ -24,3 +24,8 @@ indent_style = tab [.travis.yml] indent_style = space indent_size = 2 + +# Matches exact files +[CMakeLists.txt] +indent_style = space +indent_size = 2 diff --git a/.gitignore b/.gitignore index d5e8e1b10..75ec9a227 100644 --- a/.gitignore +++ b/.gitignore @@ -25,6 +25,7 @@ ipch/ *.user *~ +*.pyc *.bak bin/ build*/ @@ -36,6 +37,7 @@ Thumbs.db *.cfg *.cmd tmp/ +tests/orders.txt tests/config.lua tests/reports/ tests/data/185.dat diff --git a/.travis.yml b/.travis.yml index 62e60194f..c6a21d0e4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,6 +8,7 @@ addons: apt: packages: - libbsd-dev + - libdb-dev - liblua5.1-dev - libtolua-dev - libncurses5-dev diff --git a/conf/e3/config.json b/conf/e3/config.json index b4b6d0e48..dcc3e9f53 100644 --- a/conf/e3/config.json +++ b/conf/e3/config.json @@ -28,7 +28,6 @@ "stealth", "taxation", "trade", - "besiege", "steal", "buy", "teach", diff --git a/conf/keywords.json b/conf/keywords.json index 4f8f27f5b..11376ea95 100644 --- a/conf/keywords.json +++ b/conf/keywords.json @@ -12,7 +12,6 @@ "work": [ "ARBEITE", "ARBEITEN" ], "attack": ["ATTACKIERE", "ATTACKIEREN"], "steal": [ "BEKLAUE", "BEKLAUEN" ], - "besiege": ["BELAGERE", "BELAGERN" ], "name": [ "BENENNE", "BENENNEN" ], "use": [ "BENUTZE", "BENUTZEN" ], "describe": [ "BESCHREIBE", "BESCHREIBEN" ], diff --git a/process/CMakeLists.txt b/process/CMakeLists.txt index 0ffb7b4a2..bbd9b8c38 100644 --- a/process/CMakeLists.txt +++ b/process/CMakeLists.txt @@ -1,7 +1,7 @@ install(PROGRAMS create-orders backup-eressea run-turn send-zip-report send-bz2-report compress.py compress.sh epasswd.py orders-process -process-orders.py accept-orders.py -checkpasswd.py sendreport.sh sendreports.sh orders-accept DESTINATION bin) +process-orders.py accept-orders.py getemail.py checkpasswd.py +sendreport.sh sendreports.sh orders-accept DESTINATION bin) install(DIRECTORY cron/ DESTINATION bin USE_SOURCE_PERMISSIONS FILES_MATCHING PATTERN "*.cron") diff --git a/process/checkpasswd.py b/process/checkpasswd.py index f797dcfde..dd4924b32 100755 --- a/process/checkpasswd.py +++ b/process/checkpasswd.py @@ -6,14 +6,19 @@ from epasswd import EPasswd if len(sys.argv)<4: sys.exit(-2) -passfile=sys.argv[1] +filename=sys.argv[1] myfaction=sys.argv[2] mypasswd=sys.argv[3] -if mypasswd[0]=='"': - mypasswd=mypasswd[1:len(mypasswd)-1] +if mypasswd[0] == '"': + mypasswd = mypasswd.strip('"') + +pw_data = EPasswd() +try: + pw_data.load_database(filename) +except: + pw_data.load_file(filename) -pw_data=EPasswd(passfile) if pw_data.fac_exists(myfaction): if pw_data.check(myfaction, mypasswd): sys.exit(0) diff --git a/process/epasswd.py b/process/epasswd.py index aa3d79fa6..4cac6e1ce 100755 --- a/process/epasswd.py +++ b/process/epasswd.py @@ -4,47 +4,82 @@ from string import split from string import strip from string import lower import subprocess +import bcrypt +import sqlite3 + +def baseconvert(n, base): + """convert positive decimal integer n to equivalent in another base (2-36)""" + + digits = "0123456789abcdefghijkLmnopqrstuvwxyz" + + try: + n = int(n) + base = int(base) + except: + return "" + + if n < 0 or base < 2 or base > 36: + return "" + + s = "" + while True: + r = n % base + s = digits[r] + s + n = n / base + if n == 0: + break + + return s class EPasswd: - def _check_apr1(self, pwhash, pw): - spl = split(pwhash, '$') - salt = spl[2] - hash = subprocess.check_output(['openssl', 'passwd', '-apr1', '-salt', salt, pw]).decode('utf-8').strip() - return hash==pwhash + def __init__(self): + self.data = {} - def __init__(self, file): - self.data = {} - try: - fp = open(file,"r") - except: - fp = None - if fp != None: - while True: - line = fp.readline() - if not line: break - line = strip(line) - [id, email, passwd] = split(line, ":")[0:3] - lc_id = lower(id) - self.data[lc_id] = {} - self.data[lc_id]["id"] = id - self.data[lc_id]["email"] = email - self.data[lc_id]["passwd"] = passwd - fp.close() + def set_data(self, no, email, passwd): + lc_id = lower(no) + self.data[lc_id] = {} + self.data[lc_id]["id"] = no + self.data[lc_id]["email"] = email + self.data[lc_id]["passwd"] = passwd - def check(self, id, passwd): - pw = self.get_passwd(id) - if pw[0:6]=='$apr1$': - return self._check_apr1(pw, passwd) - return pw == passwd + def load_database(self, file): + conn = sqlite3.connect(file) + c = conn.cursor() + c.execute('SELECT MAX(turn) FROM factions') + args = c.fetchone() + for row in c.execute('SELECT no, email, password FROM factions WHERE turn=?', args): + (no, email, passwd) = row + self.set_data(baseconvert(no, 36), email, passwd) + conn.close() - def get_passwd(self, id): - return self.data[lower(id)]["passwd"] - - def get_email(self, id): - return self.data[lower(id)]["email"] - - def get_canon_id(self, id): - return self.data[lower(id)]["id"] + def load_file(self, file): + try: + fp = open(file,"r") + except: + fp = None + if fp != None: + while True: + line = fp.readline() + if not line: break + line = strip(line) + [id, email, passwd] = split(line, ":")[0:3] + self.set_data(id, email, passwd) + fp.close() - def fac_exists(self, id): - return self.data.has_key(lower(id)) + def check(self, id, passwd): + pw = self.get_passwd(id) + if pw[0:4]=='$2a$' or pw[0:4]=='$2y$': + return bcrypt.checkpw(passwd, pw) + return pw == passwd + + def get_passwd(self, id): + return self.data[lower(id)]["passwd"] + + def get_email(self, id): + return self.data[lower(id)]["email"] + + def get_canon_id(self, id): + return self.data[lower(id)]["id"] + + def fac_exists(self, id): + return self.data.has_key(lower(id)) diff --git a/process/getemail.py b/process/getemail.py new file mode 100755 index 000000000..d9951bcb0 --- /dev/null +++ b/process/getemail.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python + +import sys, re +from epasswd import EPasswd + +if len(sys.argv)<3: + sys.exit(-2) + +filename=sys.argv[1] +myfaction=sys.argv[2] + +pw_data = EPasswd() +try: + pw_data.load_database(filename) +except: + pw_data.load_file(filename) + +if pw_data.fac_exists(myfaction): + email = pw_data.get_email(myfaction) + print(email) + sys.exit(0) +sys.exit(-1) diff --git a/process/process-orders.py b/process/process-orders.py index 8ed5e8625..3c741bfeb 100755 --- a/process/process-orders.py +++ b/process/process-orders.py @@ -128,7 +128,11 @@ def echeck(filename, locale, rules): return mail #print "reading password file..." -pw_data = EPasswd(os.path.join(game_dir,"passwd")) +pw_data = EPasswd() +try: + pw_data.load_database(os.path.join(game_dir,"eressea.db")) +except: + pw_data.load_file(os.path.join(game_dir,"passwd")) #print "reading orders.queue..." # move the queue file to a save space while locking it: diff --git a/process/procmail/rules b/process/procmail/rules index 32626fe56..7c70c84bb 100644 --- a/process/procmail/rules +++ b/process/procmail/rules @@ -2,26 +2,6 @@ ## Eressea Reportversand ## -:0:server.lock -* ^Subject:.*ERE.*2.*PASSWOR.* -| sendpassword.py $HOME/eressea/game-2/passwd - -:0:server.lock -* ^Subject:.*ERE.*3.*PASSWOR.* -| sendpassword.py $HOME/eressea/game-3/passwd - -:0:server.lock -* ^Subject:.*ERE.*4.*PASSWOR.* -| sendpassword.py $HOME/eressea/game-4/passwd - -:0:server.lock -* ^Subject:.*ERE.*PASSWOR.* -| sendpassword.py $HOME/eressea/game-2/passwd - -:0:server.lock -* ^Subject:.*E3.*PASSWOR.* -| sendpassword.py $HOME/eressea/game-3/passwd - :0:server.lock * ^Subject:.*ERE.*2.*REPORT \/.* * !From: .*eressea.*@eressea.de diff --git a/process/sendreport.sh b/process/sendreport.sh index d98ed505e..7b1afccf0 100755 --- a/process/sendreport.sh +++ b/process/sendreport.sh @@ -30,7 +30,11 @@ LOCKFILE="$ERESSEA/.report.lock" echo "$(date):report:$GAME:$EMAIL:$FACTION:$PASSWD" >> "$ERESSEA/request.log" cd "$ERESSEA" || exit -checkpasswd.py "game-$GAME/passwd" "$FACTION" "$PASSWD" || reply "Das Passwort fuer die Partei $FACTION ist ungueltig" +PWFILE="game-$GAME/eressea.db" +if [ ! -e "$PWFILE" ]; then + PWFILE="game-$GAME/passwd" +fi +checkpasswd.py "$PWFILE" "$FACTION" "$PASSWD" || reply "Das Passwort fuer die Partei $FACTION ist ungueltig" cd "$ERESSEA/game-$GAME/reports" || exit if [ ! -e "${FACTION}.sh" ]; then @@ -41,12 +45,8 @@ fi bash "${FACTION}.sh" "$EMAIL" || reply "Unbekannte Partei $FACTION" -if [ -e "$ERESSEA/game-$GAME/eressea.db" ]; then - SQL="select email from faction f left join faction_data fd on fd.faction_id=f.id where f.game_id=$GAME AND fd.code='$FACTION' and fd.turn=(select max(turn) from faction_data fx where fx.faction_id=f.id)" - OWNER=$(sqlite3 "$ERESSEA/game-$GAME/eressea.db" "$SQL") - if [ ! -z "$OWNER" ]; then - echo "Der Report Deiner Partei wurde an ${EMAIL} gesandt." \ - | mutt -s "Reportnachforderung Partei ${FACTION}" "$OWNER" - fi +OWNER=$(getfaction.py "$PWFILE" "$FACTION") +if [ ! -z "$OWNER" ]; then + echo "Der Report Deiner Partei wurde an ${EMAIL} gesandt." \ + | mutt -s "Reportnachforderung Partei ${FACTION}" "$OWNER" fi - diff --git a/res/core/messages.xml b/res/core/messages.xml index 1e4e977e0..d2c40f9b3 100644 --- a/res/core/messages.xml +++ b/res/core/messages.xml @@ -710,12 +710,6 @@ - - - - - - @@ -2684,19 +2678,6 @@ - - - - - - - - - - - - - @@ -3351,14 +3332,6 @@ - - - - - - - - @@ -3890,13 +3863,6 @@ - - - - - - - @@ -4002,13 +3968,6 @@ - - - - - - - @@ -4993,20 +4952,6 @@ - - - - - - - - - - - - - - diff --git a/res/translations/messages.de.po b/res/translations/messages.de.po index 507f0e39d..76ff0afc9 100644 --- a/res/translations/messages.de.po +++ b/res/translations/messages.de.po @@ -257,9 +257,6 @@ msgstr "\"$unit($unit) in $region($region): '$order($command)' - Hier kann man k msgid "error165" msgstr "\"$unit($unit) in $region($region): '$order($command)' - Der Trank bekommt der Einheit nicht.\"" -msgid "siege_catapults" -msgstr "\"$unit($unit) belagert $building($building). Dabei richten die Katapulte Zerstörungen von $int($destruction) Größenpunkten an.\"" - msgid "curseinfo::magicstreet" msgstr "\"Die Straßen sind erstaunlich trocken und gut begehbar. ($int36($id))\"" @@ -638,9 +635,6 @@ msgstr "\"$unit($unit) erscheint plötzlich.\"" msgid "magicresistance_effect" msgstr "\"$unit($unit) wird kurz von einem magischen Licht umhüllt.\"" -msgid "siege" -msgstr "\"$unit($unit) belagert $building($building).\"" - msgid "missing_force" msgstr "\"$unit($unit) schafft es nicht, genug Kraft aufzubringen, um $spell($spell) auf Stufe $int($level) zu zaubern.\"" @@ -977,9 +971,6 @@ msgstr "\"$unit($mage) kümmert sich um die Verletzten und benutzt ein $resource msgid "error276" msgstr "\"$unit($unit) in $region($region): '$order($command)' - Hier kann man keine Schiffe bauen.\"" -msgid "error166" -msgstr "\"$unit($unit) in $region($region): '$order($command)' - Diese Rasse kann eine Burg nicht belagern.\"" - msgid "chaosgate_effect_2" msgstr "\"Ein Wirbel aus blendendem Licht erscheint.\"" @@ -998,9 +989,6 @@ msgstr "\"$unit($unit) in $region($region): '$order($command)' - Die Einheit ist msgid "error82" msgstr "\"$unit($unit) in $region($region): '$order($command)' - Es gibt keine Abstimmung mit dieser Nummer.\"" -msgid "error60" -msgstr "\"$unit($unit) in $region($region): '$order($command)' - Die Einheit wird belagert.\"" - msgid "error162" msgstr "\"$unit($unit) in $region($region): '$order($command)' - Der Heiltrank wird automatisch bei Bedarf benutzt.\"" @@ -1457,9 +1445,6 @@ msgstr "\"$unit($unit) öffnet eines der Schlösser in $region($region) mit $if( msgid "error255" msgstr "\"$unit($unit) in $region($region): '$order($command)' - So etwas kann man nicht opfern.\"" -msgid "entrance_besieged" -msgstr "\"$unit($unit) in $region($region): '$order($command)' - $building($building) wird belagert.\"" - msgid "error260" msgstr "\"$unit($unit) in $region($region): '$order($command)' - Der Besitzer eines Schiffes oder Gebäudes kann nicht neu sortiert werden.\"" @@ -1550,9 +1535,6 @@ msgstr "\"In $region($region) findet ein Kampf statt.\"" msgid "wormhole_dissolve" msgstr "\"Das Wurmloch in $region($region) schließt sich.\"" -msgid "error23" -msgstr "\"$unit($unit) in $region($region): '$order($command)' - Der Belagerungszustand macht die Kontaktaufnahme unmöglich.\"" - msgid "error12" msgstr "\"$unit($unit) in $region($region): '$order($command)' - Das Schiff gehört uns nicht.\"" @@ -2135,9 +2117,6 @@ msgstr "\"Seit $int($age) Wochen Mitglied der Allianz '$name ($int36($id))', ang msgid "deathcloud_effect" msgstr "\"$unit($mage) beschwört einen Giftelementar in $region($region).\"" -msgid "nr_building_besieged" -msgstr "\", belagert von $int($soldiers) Personen$if($lt($diff,0),\"\",\" (abgeschnitten)\")\"" - msgid "nr_population" msgstr "\"Deine Partei hat $int($population) Personen in $int($units) von maximal $int($limit) Einheiten.\"" @@ -2414,9 +2393,6 @@ msgstr "\"$unit($unit) in $region($region): '$order($command)' - Das Schiff hat msgid "aborted_battle" msgstr "\"Der Kampf wurde abgebrochen, da alle Verteidiger flohen.\"" -msgid "error24" -msgstr "\"$unit($unit) in $region($region): '$order($command)' - Der Belagerungszustand macht Spionage unmöglich.\"" - msgid "usecatapult" msgstr "\"$int($amount) Krieger von $unit($unit) feuern ihre Katapulte ab.\"" diff --git a/res/translations/messages.en.po b/res/translations/messages.en.po index bf9d8e3c9..50108fc03 100644 --- a/res/translations/messages.en.po +++ b/res/translations/messages.en.po @@ -257,9 +257,6 @@ msgstr "\"$unit($unit) in $region($region): '$order($command)' - Buildings canno msgid "error165" msgstr "\"$unit($unit) in $region($region): '$order($command)' - The potion does not agree with the unit.\"" -msgid "siege_catapults" -msgstr "\"$building($building) is under siege by $unit($unit). During siege, catapults caused $int($destruction) points destruction.\"" - msgid "curseinfo::magicstreet" msgstr "\"The roads are extremely dry and well-kept. ($int36($id))\"" @@ -638,9 +635,6 @@ msgstr "\"$unit($unit) appears.\"" msgid "magicresistance_effect" msgstr "\"$unit($unit) is briefly surrounded by a magical light.\"" -msgid "siege" -msgstr "\"$building($building) is under siege by $unit($unit).\"" - msgid "missing_force" msgstr "\"$unit($unit) cannot muster enough energy to cast $spell($spell) on level $int($level).\"" @@ -977,9 +971,6 @@ msgstr "\"$unit($mage) sees after the wounded and heals $int($amount). A $resour msgid "error276" msgstr "\"$unit($unit) in $region($region): '$order($command)' - Ships cannot be built here.\"" -msgid "error166" -msgstr "\"$unit($unit) in $region($region): '$order($command)' - This race cannot besiege a castle.\"" - msgid "chaosgate_effect_2" msgstr "\"A vortex of blinding light appears.\"" @@ -998,9 +989,6 @@ msgstr "\"'$order($command)' - $unit($unit) marched into $region($region) during msgid "error82" msgstr "\"$unit($unit) in $region($region): '$order($command)' - There is no agreement with this number.\"" -msgid "error60" -msgstr "\"$unit($unit) in $region($region): '$order($command)' - The unit is under siege.\"" - msgid "error162" msgstr "\"$unit($unit) in $region($region): '$order($command)' - This healing potion will be automatically used when needed.\"" @@ -1457,9 +1445,6 @@ msgstr "\"$unit($unit) unlocks one of the locks in $region($region) with $if($eq msgid "error255" msgstr "\"$unit($unit) in $region($region): '$order($command)' - You cannot sacrifice this.\"" -msgid "entrance_besieged" -msgstr "\"$unit($unit) in $region($region): '$order($command)' - $building($building) is under siege.\"" - msgid "error260" msgstr "\"$unit($unit) in $region($region): '$order($command)' - The owner of a ship or a building cannot be sorted.\"" @@ -1550,9 +1535,6 @@ msgstr "\"There is a battle in $region($region).\"" msgid "wormhole_dissolve" msgstr "\"The wormhole in $region($region) disappears.\"" -msgid "error23" -msgstr "\"$unit($unit) in $region($region): '$order($command)' - Contact was not possible due to siege.\"" - msgid "error12" msgstr "\"$unit($unit) in $region($region): '$order($command)' - The ship is not ours.\"" @@ -2135,9 +2117,6 @@ msgstr "\"Member of '$name ($int36($id))' for $int($age) weeks, led by $faction( msgid "deathcloud_effect" msgstr "\"$unit($mage) summons a poison elemental in $region($region).\"" -msgid "nr_building_besieged" -msgstr "\", besieged by $int($soldiers) soldiers$if($lt($diff,0),\"\",\" (cut off)\")\"" - msgid "nr_population" msgstr "\"Your faction has $int($population) people in $int($units) of $int($limit) possible units.\"" @@ -2414,9 +2393,6 @@ msgstr "\"$unit($unit) in $region($region): '$order($command)' - The ship has mo msgid "aborted_battle" msgstr "\"The battle was aborted because all enemies escaped.\"" -msgid "error24" -msgstr "\"$unit($unit) in $region($region): '$order($command)' - Espionage was not possible due to siege.\"" - msgid "usecatapult" msgstr "\"$int($amount) fighters of $unit($unit) launch their catapults.\"" diff --git a/res/translations/strings.de.po b/res/translations/strings.de.po index f4b166221..89875baf5 100644 --- a/res/translations/strings.de.po +++ b/res/translations/strings.de.po @@ -1437,7 +1437,7 @@ msgstr "Goblins" msgctxt "spellinfo" msgid "song_of_slavery" -msgstr "Dieser mächtige Bann raubt dem Opfer seinen freien Willen und unterwirft sie den Befehlen des Barden. Für einige Zeit wird das Opfer sich völlig von seinen eigenen Leuten abwenden und der Partei des Barden zugehörig fühlen." +msgstr "Dieser mächtige Bann raubt dem Opfer seinen freien Willen und unterwirft es den Befehlen des Barden. Für einige Zeit wird das Opfer sich völlig von seinen eigenen Leuten abwenden und der Partei des Barden zugehörig fühlen." msgctxt "spell" msgid "healingzone" @@ -2772,10 +2772,6 @@ msgstr "Dieser wunderschoen geschmueckte Baum entfaltet in den Wintermonaten ein msgid "h10" msgstr "Kakteenschwitz" -msgctxt "keyword" -msgid "besiege" -msgstr "BELAGERE" - msgid "h11" msgstr "Sandfäule" diff --git a/res/translations/strings.en.po b/res/translations/strings.en.po index 32924310c..8a5dcb30f 100644 --- a/res/translations/strings.en.po +++ b/res/translations/strings.en.po @@ -2421,10 +2421,6 @@ msgctxt "iteminfo" msgid "xmastree" msgstr "In the winter months, this beautifully decorated tree has a magical effect on the entire forest." -msgctxt "keyword" -msgid "besiege" -msgstr "BESIEGE" - msgid "h10" msgstr "peyote" diff --git a/s/cmake-init b/s/cmake-init index 337490f07..eea222334 100755 --- a/s/cmake-init +++ b/s/cmake-init @@ -1,16 +1,46 @@ #!/bin/sh -ERESSEA_DB=db -if [ -e /usr/include/sqlite3.h ] ; then -ERESSEA_DB=sqlite +ERESSEA_DB=memory +pkg-config --exists sqlite3 && ERESSEA_DB=sqlite + +GETOPT=getopt +GETOPT_LONG=1 + +if [ "Darwin" = "$(uname)" ] ; then + if [ -x "/usr/local/opt/gnu-getopt/bin/getopt" ] ; then + GETOPT="/usr/local/opt/gnu-getopt/bin/getopt" + else + GETOPT_LONG=0 + fi +fi + +if [ $GETOPT_LONG -eq 1 ]; then + options=$(${GETOPT} -o d: -l db: -- "$@") +else # assume GNU getopt (long arguments) + options=$(${GETOPT} d: "$@") fi # Parse command line arguments +eval set -- "$options" +until [ -z "$1" ] ; do + case $1 in + -d|--db) + ERESSEA_DB=$2 + shift + ;; + --) shift; break;; + (-*) echo "$0: error - unrecognized option $1" 1>&2; exit 1;; + (*) break;; + esac + shift +done while [ ! -z "$1" ] ; do if [ "$1" = "--with-db" ] ; then ERESSEA_DB=db elif [ "$1" = "--with-sqlite" ] ; then ERESSEA_DB=sqlite +elif [ "$1" = "--with-memory" ] ; then +ERESSEA_DB=memory fi shift 1 done diff --git a/s/preview b/s/preview index 39d5466d0..2fde22cda 100755 --- a/s/preview +++ b/s/preview @@ -22,11 +22,12 @@ exit $2 # otherwise function build() { assert_dir $SOURCE cd $SOURCE -rm -rf crypto tolua +rm -rf tolua git fetch || abort "failed to update source. do you have local changes?" [ -z $1 ] || git checkout $1 git pull -q git submodule update +s/cmake-init s/build > /dev/null || abort "build failed." } @@ -54,7 +55,8 @@ cd $TESTROOT cat >| eressea.ini < -#include +#include "platform.h" +#include "kernel/config.h" #include #include #include diff --git a/src/alchemy.c b/src/alchemy.c index 4b7e961a6..1673d5196 100644 --- a/src/alchemy.c +++ b/src/alchemy.c @@ -33,8 +33,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include /* util includes */ -#include -#include +#include +#include #include #include #include @@ -66,7 +66,8 @@ void new_potiontype(item_type * itype, int level) { potion_type *ptype; - ptype = (potion_type *)calloc(sizeof(potion_type), 1); + ptype = (potion_type *)calloc(1, sizeof(potion_type)); + assert(ptype); itype->flags |= ITF_POTION; ptype->itype = itype; ptype->level = level; @@ -181,7 +182,7 @@ int use_potion(unit * u, const item_type * itype, int amount, struct order *ord) static void a_initeffect(variant *var) { - var->v = calloc(sizeof(effect_data), 1); + var->v = calloc(1, sizeof(effect_data)); } static void diff --git a/src/alchemy.test.c b/src/alchemy.test.c index 32024ba1c..e7d9206c4 100644 --- a/src/alchemy.test.c +++ b/src/alchemy.test.c @@ -44,16 +44,16 @@ static void test_herbsearch(CuTest * tc) CuAssertPtrEquals(tc, u2, is_guarded(r, u)); herbsearch(u, INT_MAX); CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error70")); - CuAssertPtrEquals(tc, 0, test_find_messagetype(f->msgs, "error59")); + CuAssertPtrEquals(tc, NULL, test_find_messagetype(f->msgs, "error59")); test_clear_messages(f); setguard(u2, false); - CuAssertPtrEquals(tc, 0, is_guarded(r, u)); - CuAssertPtrEquals(tc, 0, (void *)rherbtype(r)); + CuAssertPtrEquals(tc, NULL, is_guarded(r, u)); + CuAssertPtrEquals(tc, NULL, (void *)rherbtype(r)); herbsearch(u, INT_MAX); CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error108")); - CuAssertPtrEquals(tc, 0, test_find_messagetype(f->msgs, "error70")); - CuAssertPtrEquals(tc, 0, test_find_messagetype(f->msgs, "error59")); + CuAssertPtrEquals(tc, NULL, test_find_messagetype(f->msgs, "error70")); + CuAssertPtrEquals(tc, NULL, test_find_messagetype(f->msgs, "error59")); test_clear_messages(f); rsetherbtype(r, itype); @@ -61,9 +61,9 @@ static void test_herbsearch(CuTest * tc) CuAssertIntEquals(tc, 0, rherbs(r)); herbsearch(u, INT_MAX); CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "researchherb_none")); - CuAssertPtrEquals(tc, 0, test_find_messagetype(f->msgs, "error108")); - CuAssertPtrEquals(tc, 0, test_find_messagetype(f->msgs, "error70")); - CuAssertPtrEquals(tc, 0, test_find_messagetype(f->msgs, "error59")); + CuAssertPtrEquals(tc, NULL, test_find_messagetype(f->msgs, "error108")); + CuAssertPtrEquals(tc, NULL, test_find_messagetype(f->msgs, "error70")); + CuAssertPtrEquals(tc, NULL, test_find_messagetype(f->msgs, "error59")); test_clear_messages(f); rsetherbs(r, 100); @@ -72,10 +72,10 @@ static void test_herbsearch(CuTest * tc) CuAssertIntEquals(tc, 99, rherbs(r)); CuAssertIntEquals(tc, 1, i_get(u->items, itype)); CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "herbfound")); - CuAssertPtrEquals(tc, 0, test_find_messagetype(f->msgs, "researchherb_none")); - CuAssertPtrEquals(tc, 0, test_find_messagetype(f->msgs, "error108")); - CuAssertPtrEquals(tc, 0, test_find_messagetype(f->msgs, "error70")); - CuAssertPtrEquals(tc, 0, test_find_messagetype(f->msgs, "error59")); + CuAssertPtrEquals(tc, NULL, test_find_messagetype(f->msgs, "researchherb_none")); + CuAssertPtrEquals(tc, NULL, test_find_messagetype(f->msgs, "error108")); + CuAssertPtrEquals(tc, NULL, test_find_messagetype(f->msgs, "error70")); + CuAssertPtrEquals(tc, NULL, test_find_messagetype(f->msgs, "error59")); test_clear_messages(f); test_teardown(); diff --git a/src/attributes/attributes.c b/src/attributes/attributes.c index fa6f15d73..12cb9131f 100644 --- a/src/attributes/attributes.c +++ b/src/attributes/attributes.c @@ -53,9 +53,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include /* util includes */ -#include -#include -#include +#include +#include +#include #include #include @@ -98,7 +98,7 @@ static int obs_read(variant *var, void *owner, struct gamedata *data) obs_data *od = (obs_data *)var->v; UNUSED_ARG(owner); - read_faction_reference(data, &od->f, NULL); + read_faction_reference(data, &od->f); READ_INT(data->store, &od->skill); READ_INT(data->store, &od->timer); return AT_READ_OK; @@ -182,13 +182,13 @@ void register_attributes(void) at_register(&at_seenspell); at_register(&at_seenspells); - /* neue REGION-Attribute */ + /* REGION Attribute */ at_register(&at_moveblock); at_register(&at_deathcount); at_register(&at_woodcount); + at_register(&at_germs); - /* neue UNIT-Attribute */ - at_register(&at_siege); + /* UNIT Attribute */ at_register(&at_effect); at_register(&at_private); @@ -205,8 +205,7 @@ void register_attributes(void) register_bordertype(&bt_illusionwall); register_bordertype(&bt_road); - at_register(&at_germs); - + at_deprecate("siege", a_readint); at_deprecate("maxmagicians", a_readint); /* factions with differnt magician limits, probably unused */ at_deprecate("hurting", a_readint); /* an old arena attribute */ at_deprecate("chaoscount", a_readint); /* used to increase the chance of monster spawns */ diff --git a/src/attributes/dict.c b/src/attributes/dict.c index bc5e94204..70e88219d 100644 --- a/src/attributes/dict.c +++ b/src/attributes/dict.c @@ -29,10 +29,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include /* util includes */ -#include +#include #include #include -#include +#include #include #include diff --git a/src/attributes/follow.c b/src/attributes/follow.c index 8c5e14526..caeecee54 100644 --- a/src/attributes/follow.c +++ b/src/attributes/follow.c @@ -22,8 +22,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include -#include -#include +#include +#include #include #include diff --git a/src/attributes/hate.c b/src/attributes/hate.c index c260de335..cef483cf6 100644 --- a/src/attributes/hate.c +++ b/src/attributes/hate.c @@ -22,8 +22,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include -#include -#include +#include +#include #include #include diff --git a/src/attributes/iceberg.c b/src/attributes/iceberg.c index e36e6303a..192ae9032 100644 --- a/src/attributes/iceberg.c +++ b/src/attributes/iceberg.c @@ -20,7 +20,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include "iceberg.h" -#include +#include attrib_type at_iceberg = { "iceberg_drift", diff --git a/src/attributes/key.c b/src/attributes/key.c index 75958a6fb..76a18c876 100644 --- a/src/attributes/key.c +++ b/src/attributes/key.c @@ -20,11 +20,12 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include "key.h" -#include -#include +#include +#include #include #include +#include #include #include #include @@ -76,25 +77,83 @@ static int keys_size(int n) { return 4096; } +static int read_flags(gamedata *data, int *keys, int n) { + int i; + for (i = 0; i != n; ++i) { + int key; + READ_INT(data->store, &key); + keys[i * 2] = key; + keys[i * 2 + 1] = 1; + } + return n; +} + +#ifdef KEYVAL_VERSION +static int read_keyval(gamedata *data, int *keys, int n) { + int i; + for (i = 0; i != n; ++i) { + int key, val; + READ_INT(data->store, &key); + READ_INT(data->store, &val); + keys[i * 2] = key; + keys[i * 2 + 1] = val; + } + return n; +} +#endif + +#ifdef FIXATKEYS_VERSION +static int read_keyval_orig(gamedata *data, int *keys, int n) { + int i, j = 0, dk = -1; + for (i = 0; i != n; ++i) { + int key, val; + READ_INT(data->store, &key); + READ_INT(data->store, &val); + if (key > dk) { + keys[j * 2] = key; + keys[j * 2 + 1] = val; + dk = key; + ++j; + } + } + return j; +} +#endif + static int a_readkeys(variant *var, void *owner, gamedata *data) { - int i, n, *keys; + int i, n, ksn, *keys; READ_INT(data->store, &n); assert(n < 4096 && n >= 0); if (n == 0) { return AT_READ_FAIL; } - keys = malloc(sizeof(int)*(keys_size(n) * 2 + 1)); - *keys = n; - for (i = 0; i != n; ++i) { - READ_INT(data->store, keys + i * 2 + 1); - if (data->version >= KEYVAL_VERSION) { - READ_INT(data->store, keys + i * 2 + 2); - } - else { - keys[i * 2 + 2] = 1; + ksn = keys_size(n); + keys = malloc((ksn * 2 + 1) * sizeof(int)); + if (data->version >= FIXATKEYS_VERSION) { + n = read_keyval(data, keys + 1, n); + } + else if (data->version >= KEYVAL_VERSION) { + int m = read_keyval_orig(data, keys + 1, n); + if (n != m) { + int ksm = keys_size(m); + if (ksm != ksn) { + int *nkeys = (int *)realloc(keys, (ksm * 2 + 1) * sizeof(int)); + if (nkeys != NULL) { + keys = nkeys; + } + else { + log_error("a_readkeys allocation failed: %s", strerror(errno)); + return AT_READ_FAIL; + } + } + n = m; } } + else { + n = read_flags(data, keys + 1, n); + } + keys[0] = n; if (data->version < SORTKEYS_VERSION) { int e = 1; for (i = 1; i != n; ++i) { diff --git a/src/attributes/key.test.c b/src/attributes/key.test.c index 79a7bde1d..fc09fc391 100644 --- a/src/attributes/key.test.c +++ b/src/attributes/key.test.c @@ -2,7 +2,7 @@ #include "key.h" #include "dict.h" -#include +#include #include #include #include diff --git a/src/attributes/movement.c b/src/attributes/movement.c index 7b49291c2..01c75ffae 100644 --- a/src/attributes/movement.c +++ b/src/attributes/movement.c @@ -20,8 +20,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include "movement.h" -#include -#include +#include +#include #include #include diff --git a/src/attributes/otherfaction.c b/src/attributes/otherfaction.c index 343460057..fcf05da05 100644 --- a/src/attributes/otherfaction.c +++ b/src/attributes/otherfaction.c @@ -23,8 +23,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include -#include -#include +#include +#include #include #include diff --git a/src/attributes/otherfaction.test.c b/src/attributes/otherfaction.test.c index 8417ed3e3..e4f7c95b9 100644 --- a/src/attributes/otherfaction.test.c +++ b/src/attributes/otherfaction.test.c @@ -7,7 +7,7 @@ #include #include -#include +#include #include #include diff --git a/src/attributes/overrideroads.c b/src/attributes/overrideroads.c index ef466de2d..d96d115d9 100644 --- a/src/attributes/overrideroads.c +++ b/src/attributes/overrideroads.c @@ -20,7 +20,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include "overrideroads.h" -#include +#include attrib_type at_overrideroads = { "roads_override", NULL, NULL, NULL, a_writestring, a_readstring diff --git a/src/attributes/racename.c b/src/attributes/racename.c index c46fb0c4b..9374f1238 100644 --- a/src/attributes/racename.c +++ b/src/attributes/racename.c @@ -20,7 +20,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include "racename.h" -#include +#include #include /* libc includes */ diff --git a/src/attributes/raceprefix.c b/src/attributes/raceprefix.c index 233d17e40..84997b909 100644 --- a/src/attributes/raceprefix.c +++ b/src/attributes/raceprefix.c @@ -20,7 +20,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include "raceprefix.h" -#include +#include #include #include diff --git a/src/attributes/reduceproduction.c b/src/attributes/reduceproduction.c index 01041380a..0ae0abbea 100644 --- a/src/attributes/reduceproduction.c +++ b/src/attributes/reduceproduction.c @@ -22,7 +22,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include -#include +#include #include static int age_reduceproduction(attrib * a, void *owner) diff --git a/src/attributes/seenspell.c b/src/attributes/seenspell.c index 82bdf22ca..ae46980c3 100644 --- a/src/attributes/seenspell.c +++ b/src/attributes/seenspell.c @@ -23,8 +23,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include -#include -#include +#include +#include #include #include diff --git a/src/attributes/stealth.c b/src/attributes/stealth.c index db2ec5304..ae00e8721 100644 --- a/src/attributes/stealth.c +++ b/src/attributes/stealth.c @@ -1,7 +1,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/attributes/targetregion.c b/src/attributes/targetregion.c index 7ef1fe84a..4f5a2101a 100644 --- a/src/attributes/targetregion.c +++ b/src/attributes/targetregion.c @@ -22,8 +22,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include -#include -#include +#include +#include #include #include @@ -36,7 +36,7 @@ write_targetregion(const variant *var, const void *owner, struct storage *store) static int read_targetregion(variant *var, void *owner, gamedata *data) { - if (read_region_reference(data, (region **)&var->v, NULL) <= 0) { + if (read_region_reference(data, (region **)&var->v) <= 0) { return AT_READ_FAIL; } return AT_READ_OK; diff --git a/src/automate.c b/src/automate.c index beb24a780..04230096d 100644 --- a/src/automate.c +++ b/src/automate.c @@ -6,10 +6,10 @@ #include "kernel/region.h" #include "kernel/unit.h" +#include "util/keyword.h" #include "util/log.h" #include "automate.h" -#include "keyword.h" #include "laws.h" #include "study.h" @@ -55,10 +55,6 @@ int autostudy_init(scholar scholars[], int max_scholars, unit **units) unext = u; } } - else { - ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "error_race_nolearn", "race", - u_race(u))); - } } u = u->next; } diff --git a/src/battle.c b/src/battle.c index 9e2f841c0..00cece5b0 100644 --- a/src/battle.c +++ b/src/battle.c @@ -60,7 +60,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* util includes */ #include -#include +#include #include #include #include @@ -100,10 +100,8 @@ typedef enum combatmagic { #define MINSPELLRANGE 1 #define MAXSPELLRANGE 7 -#ifndef ROW_FACTOR -# define ROW_FACTOR 10 -#endif -#define EFFECT_PANIC_SPELL 0.25 +#define ROW_FACTOR 3 /* factor for combat row advancement rule */ +#define EFFECT_PANIC_SPELL 25 #define TROLL_REGENERATION 0.10 /* Nach dem alten System: */ @@ -122,17 +120,21 @@ const troop no_troop = { 0, 0 }; #define DAMAGE_CRITICAL (1<<0) #define DAMAGE_MELEE_BONUS (1<<1) -#define DAMAGE_MISSILE_BONUS (1<<2) +#define DAMAGE_MISSILE_BONUS (1<<2) /* deprecated */ #define DAMAGE_SKILL_BONUS (1<<4) static int max_turns; static int rule_damage; static int rule_loot; +static int flee_chance_max_percent; +static int flee_chance_base; +static int flee_chance_skill_bonus; static int skill_formula; static int rule_cavalry_skill; static int rule_population_damage; static int rule_hero_speed; static bool rule_anon_battle; +static bool rule_igjarjuk_curse; static int rule_goblin_bonus; static int rule_tactics_formula; static int rule_nat_armor; @@ -146,12 +148,16 @@ static void init_rules(void) { it_mistletoe = it_find("mistletoe"); + flee_chance_skill_bonus = config_get_int("rules.combat.flee_chance_bonus", 5); + flee_chance_base = config_get_int("rules.combat.flee_chance_base", 20); + flee_chance_max_percent = config_get_int("rules.combat.flee_chance_limit", 90); rule_nat_armor = config_get_int("rules.combat.nat_armor", 0); rule_tactics_formula = config_get_int("rules.tactics.formula", 0); rule_goblin_bonus = config_get_int("rules.combat.goblinbonus", 10); rule_hero_speed = config_get_int("rules.combat.herospeed", 10); rule_population_damage = config_get_int("rules.combat.populationdamage", 20); rule_anon_battle = config_get_int("rules.stealth.anon_battle", 1) != 0; + rule_igjarjuk_curse = config_get_int("rules.combat.igjarjuk_curse", 0) != 0; rule_cavalry_mode = config_get_int("rules.cavalry.mode", 1); rule_cavalry_skill = config_get_int("rules.cavalry.skill", 2); rule_vampire = config_get_int("rules.combat.demon_vampire", 0); @@ -161,7 +167,7 @@ static void init_rules(void) skill_formula = config_get_int("rules.combat.skill_formula", FORMULA_ORIG); /* maximum number of combat turns */ - max_turns = config_get_int("rules.combat.turns", COMBAT_TURNS); + max_turns = config_get_int("rules.combat.turns", 5); /* damage calculation */ if (config_get_int("rules.combat.critical", 1)) { rule_damage |= DAMAGE_CRITICAL; @@ -169,7 +175,7 @@ static void init_rules(void) if (config_get_int("rules.combat.melee_bonus", 1)) { rule_damage |= DAMAGE_MELEE_BONUS; } - if (config_get_int("rules.combat.missile_bonus", 1)) { + if (config_get_int("rules.combat.missile_bonus", 1)) { /* deprecated */ rule_damage |= DAMAGE_MISSILE_BONUS; } if (config_get_int("rules.combat.skill_bonus", 1)) { @@ -277,19 +283,15 @@ static void set_friendly(side * as, side * ds) as->relations[ds->index] |= E_FRIEND; } -static int allysfm(const side * s, const faction * f, int mode) +static bool alliedside(const side * s, const faction * f, int mode) { - if (s->faction == f) - return mode; - if (s->group) { - return alliedgroup(s->battle->plane, s->faction, f, s->group->allies, mode); + if (s->faction == f) { + return true; } - return alliedfaction(s->battle->plane, s->faction, f, mode); -} - -static int allysf(const side * s, const faction * f) -{ - return allysfm(s, f, HELP_FIGHT); + if (s->group) { + return alliedgroup(s->faction, f, s->group, mode) != 0; + } + return alliedfaction(s->faction, f, mode) != 0; } static int dead_fighters(const fighter * df) @@ -309,7 +311,7 @@ fighter *select_corpse(battle * b, fighter * af) for (si = 0; si != b->nsides; ++si) { side *s = b->sides + si; - if (af == NULL || (!enemy_i(af->side, si) && allysf(af->side, s->faction))) { + if (af == NULL || (!enemy_i(af->side, si) && alliedside(af->side, s->faction, HELP_FIGHT))) { maxcasualties += s->casualties; } } @@ -340,7 +342,7 @@ bool helping(const side * as, const side * ds) { if (as->faction == ds->faction) return true; - return (bool)(!enemy(as, ds) && allysf(as, ds->faction)); + return (!enemy(as, ds) && alliedside(as, ds->faction, HELP_FIGHT)); } int statusrow(int status) @@ -486,7 +488,7 @@ contest_classic(int skilldiff, const armor_type * ar, const armor_type * sh) mod *= (1 + ar->penalty); if (sh != NULL) mod *= (1 + sh->penalty); - vw = (int)(100 - ((100 - vw) * mod)); + vw = (int)(100.0 - ((100.0 - (double)vw) * mod)); do { p = (int)(rng_int() % 100); @@ -555,8 +557,7 @@ static weapon *preferred_weapon(const troop t, bool attacking) return melee; } -static weapon *select_weapon(const troop t, bool attacking, - bool ismissile) +weapon *select_weapon(const troop t, bool attacking, bool ismissile) /* select the primary weapon for this trooper */ { if (attacking) { @@ -770,7 +771,7 @@ bool missile) return skill; } -static const armor_type *select_armor(troop t, bool shield) +const armor_type *select_armor(troop t, bool shield) { unsigned int type = shield ? ATF_SHIELD : 0; unit *u = t.fighter->unit; @@ -829,7 +830,7 @@ bool meffect_protection(battle * b, meffect * s, side * ds) return false; if (enemy(s->magician->side, ds)) return false; - if (allysf(s->magician->side, ds->faction)) + if (alliedside(s->magician->side, ds->faction, HELP_FIGHT)) return true; return false; } @@ -950,6 +951,9 @@ void drain_exp(struct unit *u, int n) static void vampirism(troop at, int damage) { + const unit *au = at.fighter->unit; + + if (u_race(au) == get_race(RC_DAEMON)) { if (rule_vampire > 0) { int gain = damage / rule_vampire; int chance = damage - rule_vampire * gain; @@ -963,6 +967,16 @@ static void vampirism(troop at, int damage) at.fighter->person[at.index].hp = maxhp; } } + } +} + +static void ship_damage(int turn, unit *du) { + if (turn>1) { + /* someone on the ship got damaged, damage the ship */ + ship *sh = du->ship ? du->ship : leftship(du); + if (sh) + fset(sh, SF_DAMAGED); + } } #define MAXRACES 128 @@ -1012,85 +1026,94 @@ static int rc_specialdamage(const unit *au, const unit *du, const struct weapon_ return modifier; } -int calculate_armor(troop dt, const weapon_type *dwtype, const weapon_type *awtype, variant *magres) { - fighter *df = dt.fighter; +int calculate_armor(troop dt, const weapon_type *dwtype, const weapon_type *awtype, + const armor_type *armor, const armor_type *shield, bool magic) { + + const fighter *df = dt.fighter; unit *du = df->unit; - int ar = 0, an, am; - const armor_type *armor = select_armor(dt, false); - const armor_type *shield = select_armor(dt, true); + int total_armor = 0, nat_armor, magic_armor; bool missile = awtype && (awtype->flags&WTF_MISSILE); if (armor) { - ar += armor->prot; + total_armor += armor->prot; if (missile && armor->projectile > 0 && chance(armor->projectile)) { return -1; } } if (shield) { - ar += shield->prot; + total_armor += shield->prot; if (missile && shield->projectile > 0 && chance(shield->projectile)) { return -1; } } + if (magic) { + /* gegen Magie wirkt nur natuerliche und magische Ruestung */ + total_armor = 0; + } + /* nat�rliche R�stung */ - an = natural_armor(du); + nat_armor = natural_armor(du); /* magische R�stung durch Artefakte oder Spr�che */ /* Momentan nur Trollg�rtel und Werwolf-Eigenschaft */ - am = select_magicarmor(dt); + magic_armor = select_magicarmor(dt); if (rule_nat_armor == 0) { /* nat�rliche R�stung ist halbkumulativ */ - if (ar > 0) { - ar += an / 2; + if (total_armor > 0) { + total_armor += nat_armor / 2; } else { - ar = an; + total_armor = nat_armor; } } else { /* use the higher value, add half the other value */ - ar = (ar > an) ? (ar + an / 2) : (an + ar / 2); + total_armor = (total_armor > nat_armor) ? (total_armor + nat_armor / 2) : (nat_armor + total_armor / 2); } if (awtype && fval(awtype, WTF_ARMORPIERCING)) { /* crossbows */ - ar /= 2; + total_armor /= 2; } - ar += am; + total_armor += magic_armor; - if (magres) { - /* calculate damage multiplier for magical damage */ - variant res; - - res = frac_sub(frac_one, magic_resistance(du)); + assert(total_armor >= 0 || !"armor < 0 means hit denied"); - if (u_race(du)->battle_flags & BF_EQUIPMENT) { - /* der Effekt von Laen steigt nicht linear */ - if (armor && fval(armor, ATF_LAEN)) { - res = frac_mul(res, frac_sub(frac_one, armor->magres)); - } - if (shield && fval(shield, ATF_LAEN)) { - res = frac_mul(res, frac_sub(frac_one, shield->magres)); - } - if (dwtype) { - res = frac_mul(res, frac_sub(frac_one, dwtype->magres)); - } - } + return total_armor; +} - /* gegen Magie wirkt nur natuerliche und magische Ruestung */ - ar = an + am; - if (res.sa[0] >= 0) { - *magres = res; - } - else { - *magres = frac_make(0, 1); - } +int apply_resistance(int damage, troop dt, const weapon_type *dwtype, const armor_type *armor, const armor_type *shield, bool magic) { + const fighter *df = dt.fighter; + unit *du = df->unit; + + if (!magic) + return damage; + + /* calculate damage multiplier for magical damage */ + variant resistance_factor = frac_sub(frac_one, magic_resistance(du)); + + if (u_race(du)->battle_flags & BF_EQUIPMENT) { + /* der Effekt von Laen steigt nicht linear */ + if (armor && fval(armor, ATF_LAEN)) { + resistance_factor = frac_mul(resistance_factor, frac_sub(frac_one, armor->magres)); } + if (shield && fval(shield, ATF_LAEN)) { + resistance_factor = frac_mul(resistance_factor, frac_sub(frac_one, shield->magres)); + } + if (dwtype) { + resistance_factor = frac_mul(resistance_factor, frac_sub(frac_one, dwtype->magres)); + } + } + if (resistance_factor.sa[0] <= 0) { + return 0; + } + + variant reduced_damage = frac_mul(frac_make(damage, 1), resistance_factor); + return reduced_damage.sa[0] / reduced_damage.sa[1]; - return ar; } static bool resurrect_troop(troop dt) @@ -1108,174 +1131,30 @@ static bool resurrect_troop(troop dt) return false; } -bool -terminate(troop dt, troop at, int type, const char *damage, bool missile) -{ - item **pitm; - fighter *df = dt.fighter; - fighter *af = at.fighter; - unit *au = af->unit; - unit *du = df->unit; - battle *b = df->side->battle; - - /* Schild */ - side *ds = df->side; - int ar; - - const weapon_type *dwtype = NULL; - const weapon_type *awtype = NULL; - const weapon *weapon; - variant res = frac_one; - - int rda, sk = 0, sd; - bool magic = false; - int da = dice_rand(damage); - - assert(du->number > 0); - ++at.fighter->hits; - - switch (type) { - case AT_STANDARD: - weapon = select_weapon(at, true, missile); - sk = weapon_effskill(at, dt, weapon, true, missile); - if (weapon) - awtype = weapon->type; - if (awtype && fval(awtype, WTF_MAGICAL)) - magic = true; - break; - case AT_NATURAL: - sk = weapon_effskill(at, dt, NULL, true, missile); - break; - case AT_SPELL: - case AT_COMBATSPELL: - magic = true; - break; - default: - break; - } - weapon = select_weapon(dt, false, true); /* missile=true to get the unmodified best weapon she has */ - sd = weapon_effskill(dt, at, weapon, false, false); - if (weapon != NULL) - dwtype = weapon->type; - - if (is_riding(at) && (awtype == NULL || (fval(awtype, WTF_HORSEBONUS) - && !fval(awtype, WTF_MISSILE)))) { - da += CavalryBonus(au, dt, BONUS_DAMAGE); - } - - ar = calculate_armor(dt, dwtype, awtype, magic ? &res : 0); - if (ar < 0) { - return false; - } - - if (magic) { - res = frac_sub(frac_one, res); - res = frac_mul(frac_make(da, 1), res); - da = res.sa[0] / res.sa[1]; - } - - if (type != AT_COMBATSPELL && type != AT_SPELL) { - if (rule_damage & DAMAGE_CRITICAL) { - double kritchance = (sk * 3 - sd) / 200.0; - int maxk = 4; - - kritchance = fmax(kritchance, 0.005); - kritchance = fmin(0.9, kritchance); - - while (maxk-- && chance(kritchance)) { - da += dice_rand(damage); - } - } - - da += rc_specialdamage(au, du, awtype); - - if (awtype != NULL && fval(awtype, WTF_MISSILE)) { - /* missile weapon bonus */ - if (rule_damage & DAMAGE_MISSILE_BONUS) { - da += af->person[at.index].damage_rear; - } - } - else { - /* melee bonus */ - if (rule_damage & DAMAGE_MELEE_BONUS) { - da += af->person[at.index].damage; - } - } - - /* Skilldifferenzbonus */ - if (rule_damage & DAMAGE_SKILL_BONUS) { - da += MAX(0, (sk - sd) / DAMAGE_QUOTIENT); +static void demon_dazzle(fighter *af, troop dt) { + const fighter *df = dt.fighter; + if (u_race(af->unit) == get_race(RC_DAEMON)) { + if (!(df->person[dt.index].flags & (FL_COURAGE | FL_DAZZLED))) { + df->person[dt.index].flags |= FL_DAZZLED; + df->person[dt.index].defense--; } } +} - rda = MAX(da - ar, 0); +static bool survives(fighter *af, troop dt, battle *b) { + const unit *du = af->unit; + const fighter *df = dt.fighter; - if ((u_race(du)->battle_flags & BF_INV_NONMAGIC) && !magic) - rda = 0; - else { - int qi; - selist *ql; - unsigned int i = 0; - - if (u_race(du)->battle_flags & BF_RES_PIERCE) - i |= WTF_PIERCE; - if (u_race(du)->battle_flags & BF_RES_CUT) - i |= WTF_CUT; - if (u_race(du)->battle_flags & BF_RES_BASH) - i |= WTF_BLUNT; - - if (i && awtype && fval(awtype, i)) - rda /= 2; - - /* Schilde */ - for (qi = 0, ql = b->meffects; ql; selist_advance(&ql, &qi, 1)) { - meffect *me = (meffect *)selist_get(ql, qi); - if (meffect_protection(b, me, ds) != 0) { - assert(0 <= rda); /* rda sollte hier immer mindestens 0 sein */ - /* jeder Schaden wird um effect% reduziert bis der Schild duration - * Trefferpunkte aufgefangen hat */ - if (me->typ == SHIELD_REDUCE) { - int hp = rda * (me->effect / 100); - rda -= hp; - me->duration -= hp; - } - /* gibt R�stung +effect f�r duration Treffer */ - if (me->typ == SHIELD_ARMOR) { - rda = MAX(rda - me->effect, 0); - me->duration--; - } - } - } - } - - assert(dt.index >= 0 && dt.index < du->number); - if (rda>0) { - df->person[dt.index].hp -= rda; - if (u_race(au) == get_race(RC_DAEMON)) { - vampirism(at, rda); - } - if (b->turn>1) { - /* someone on the ship got damaged, damage the ship */ - ship *sh = du->ship ? du->ship : leftship(du); - if (sh) - fset(sh, SF_DAMAGED); - } - - } if (df->person[dt.index].hp > 0) { /* Hat �berlebt */ - if (u_race(au) == get_race(RC_DAEMON)) { - if (!(df->person[dt.index].flags & (FL_COURAGE | FL_DAZZLED))) { - df->person[dt.index].flags |= FL_DAZZLED; - df->person[dt.index].defence--; - } - } - return false; + demon_dazzle(af, dt); + + return true; } /* Sieben Leben */ if (u_race(du) == get_race(RC_CAT) && (chance(1.0 / 7))) { df->person[dt.index].hp = unit_max_hp(du); - return false; + return true; } /* healing potions can avert a killing blow */ @@ -1283,23 +1162,218 @@ terminate(troop dt, troop at, int type, const char *damage, bool missile) message *m = msg_message("potionsave", "unit", du); battle_message_faction(b, du->faction, m); msg_release(m); + return true; + } + + return false; +} + +static void destroy_items(troop dt) { + unit *du = dt.fighter->unit; + + item **pitm; + + for (pitm = &du->items; *pitm;) { + item *itm = *pitm; + const item_type *itype = itm->type; + if (!(itype->flags & ITF_CURSED) && dt.index < itm->number) { + /* 25% Grundchance, das ein Item kaputtgeht. */ + if (rng_int() % 4 < 1) { + i_change(pitm, itype, -1); + } + } + if (*pitm == itm) { + pitm = &itm->next; + } + } + +} + +static void calculate_defense_type(troop dt, troop at, int type, bool missile, + const weapon_type **dwtype, int *defskill) { + const weapon *weapon; + weapon = select_weapon(dt, false, true); /* missile=true to get the unmodified best weapon she has */ + *defskill = weapon_effskill(dt, at, weapon, false, false); + if (weapon != NULL) + *dwtype = weapon->type; +} + +static void calculate_attack_type(troop dt, troop at, int type, bool missile, + const weapon_type **awtype, int *attskill, bool *magic) { + const weapon *weapon; + + switch (type) { + case AT_STANDARD: + weapon = select_weapon(at, true, missile); + *attskill = weapon_effskill(at, dt, weapon, true, missile); + if (weapon) + *awtype = weapon->type; + if (*awtype && fval(*awtype, WTF_MAGICAL)) + *magic = true; + break; + case AT_NATURAL: + *attskill = weapon_effskill(at, dt, NULL, true, missile); + break; + case AT_SPELL: + case AT_COMBATSPELL: + *magic = true; + break; + default: + break; + } +} + +static int crit_damage(int attskill, int defskill, const char *damage_formula) { + int damage = 0; + if (rule_damage & DAMAGE_CRITICAL) { + double kritchance = ((double)attskill * 3.0 - (double)defskill) / 200.0; + int maxk = 4; + + kritchance = fmax(kritchance, 0.005); + kritchance = fmin(0.9, kritchance); + + while (maxk-- && chance(kritchance)) { + damage += dice_rand(damage_formula); + } + } + return damage; +} + +static int apply_race_resistance(int reduced_damage, fighter *df, + const weapon_type *awtype, bool magic) { + unit *du = df->unit; + + if ((u_race(du)->battle_flags & BF_INV_NONMAGIC) && !magic) + reduced_damage = 0; + else { + unsigned int i = 0; + + if (u_race(du)->battle_flags & BF_RES_PIERCE) + i |= WTF_PIERCE; + if (u_race(du)->battle_flags & BF_RES_CUT) + i |= WTF_CUT; + if (u_race(du)->battle_flags & BF_RES_BASH) + i |= WTF_BLUNT; + + if (i && awtype && fval(awtype, i)) + reduced_damage /= 2; + } + return reduced_damage; +} + +static int apply_magicshield(int reduced_damage, fighter *df, + const weapon_type *awtype, battle *b, bool magic) { + side *ds = df->side; + selist *ql; + int qi; + + if (reduced_damage <= 0) + return 0; + + /* Schilde */ + for (qi = 0, ql = b->meffects; ql; selist_advance(&ql, &qi, 1)) { + meffect *me = (meffect *) selist_get(ql, qi); + if (meffect_protection(b, me, ds) != 0) { + assert(0 <= reduced_damage); /* rda sollte hier immer mindestens 0 sein */ + /* jeder Schaden wird um effect% reduziert bis der Schild duration + * Trefferpunkte aufgefangen hat */ + if (me->typ == SHIELD_REDUCE) { + int hp = reduced_damage * (me->effect / 100); + reduced_damage -= hp; + me->duration -= hp; + } + /* gibt R�stung +effect f�r duration Treffer */ + if (me->typ == SHIELD_ARMOR) { + reduced_damage = MAX(reduced_damage - me->effect, 0); + me->duration--; + } + } + } + + return reduced_damage; +} + +bool +terminate(troop dt, troop at, int type, const char *damage_formula, bool missile) +{ + fighter *df = dt.fighter; + fighter *af = at.fighter; + unit *au = af->unit; + unit *du = df->unit; + battle *b = df->side->battle; + + int armor_value; + + const weapon_type *dwtype = NULL; + const weapon_type *awtype = NULL; + const armor_type *armor = NULL; + const armor_type *shield = NULL; + + int reduced_damage, attskill = 0, defskill = 0; + bool magic = false; + + int damage = dice_rand(damage_formula); + + assert(du->number > 0); + ++at.fighter->hits; + + calculate_attack_type(at, dt, type, missile, &awtype, &attskill, &magic); + calculate_defense_type(at, dt, type, missile, &awtype, &attskill); + + if (is_riding(at) && (awtype == NULL || (fval(awtype, WTF_HORSEBONUS) + && !fval(awtype, WTF_MISSILE)))) { + damage += CavalryBonus(au, dt, BONUS_DAMAGE); + } + + armor = select_armor(dt, false); + shield = select_armor(dt, true); + + armor_value = calculate_armor(dt, dwtype, awtype, armor, shield, magic); + if (armor_value < 0) { return false; } - ++at.fighter->kills; - for (pitm = &du->items; *pitm;) { - item *itm = *pitm; - const item_type *itype = itm->type; - if (!(itype->flags & ITF_CURSED) && dt.index < itm->number) { - /* 25% Grundchance, das ein Item kaputtgeht. */ - if (rng_int() % 4 < 1) { - i_change(pitm, itype, -1); + damage = apply_resistance(damage, dt, dwtype, armor, shield, magic); + + if (type != AT_COMBATSPELL && type != AT_SPELL) { + damage += crit_damage(attskill, defskill, damage_formula); + + damage += rc_specialdamage(au, du, awtype); + + if (awtype == NULL || !fval(awtype, WTF_MISSILE)) { + /* melee bonus */ + if (rule_damage & DAMAGE_MELEE_BONUS) { + damage += af->person[at.index].damage; } } - if (*pitm == itm) { - pitm = &itm->next; + + /* Skilldifferenzbonus */ + if (rule_damage & DAMAGE_SKILL_BONUS) { + damage += MAX(0, (attskill - defskill) / DAMAGE_QUOTIENT); } } + + reduced_damage = MAX(damage - armor_value, 0); + + reduced_damage = apply_race_resistance(reduced_damage, df, awtype, magic); + reduced_damage = apply_magicshield(reduced_damage, df, awtype, b, magic); + + assert(dt.index >= 0 && dt.index < du->number); + if (reduced_damage > 0) { + df->person[dt.index].hp -= reduced_damage; + + vampirism(at, reduced_damage); + + ship_damage(b->turn, du); + } + + if (survives(af, dt, b)) + return false; + + ++at.fighter->kills; + + destroy_items(dt); + kill_troop(dt); return true; @@ -1578,7 +1652,7 @@ selist *select_fighters(battle * b, const side * vs, int mask, select_fun cb, vo continue; } else if (mask == FS_HELP) { - if (enemy(s, vs) || !allysf(s, vs->faction)) { + if (enemy(s, vs) || !alliedside(s, vs->faction, HELP_FIGHT)) { continue; } } @@ -1676,13 +1750,14 @@ void do_combatmagic(battle * b, combatmagic_t was) memset(spellranks, 0, sizeof(spellranks)); - if (was == DO_PRECOMBATSPELL) { + if (rule_igjarjuk_curse && was == DO_PRECOMBATSPELL) { summon_igjarjuk(b, spellranks); } for (s = b->sides; s != b->sides + b->nsides; ++s) { fighter *fig; for (fig = s->fighters; fig; fig = fig->next) { unit *mage = fig->unit; + unit *caster = mage; if (fig->alive <= 0) continue; /* fighter kann im Kampf get�tet worden sein */ @@ -1716,7 +1791,7 @@ void do_combatmagic(battle * b, combatmagic_t was) continue; } - level = eff_spelllevel(mage, sp, level, 1); + level = eff_spelllevel(mage, caster, sp, level, 1); if (sl > 0 && sl < level) { level = sl; } @@ -1730,11 +1805,11 @@ void do_combatmagic(battle * b, combatmagic_t was) free_order(ord); if (power <= 0) { /* Effekt von Antimagie */ report_failed_spell(b, mage, sp); - pay_spell(mage, sp, level, 1); + pay_spell(mage, NULL, sp, level, 1); } else if (fumble(r, mage, sp, level)) { report_failed_spell(b, mage, sp); - pay_spell(mage, sp, level, 1); + pay_spell(mage, NULL, sp, level, 1); } else { co = create_castorder_combat(0, fig, sp, level, power); @@ -1750,7 +1825,7 @@ void do_combatmagic(battle * b, combatmagic_t was) level = cast_spell(co); if (level > 0) { - pay_spell(fig->unit, sp, level, 1); + pay_spell(fig->unit, NULL, sp, level, 1); } } } @@ -1767,7 +1842,7 @@ static int cast_combatspell(troop at, const spell * sp, int level, double force) level = cast_spell(&co); free_castorder(&co); if (level > 0) { - pay_spell(at.fighter->unit, sp, level, 1); + pay_spell(at.fighter->unit, NULL, sp, level, 1); } return level; } @@ -1776,7 +1851,7 @@ static void do_combatspell(troop at) { const spell *sp; fighter *fi = at.fighter; - unit *caster = fi->unit; + unit *mage = fi->unit; battle *b = fi->side->battle; region *r = b->region; selist *ql; @@ -1785,28 +1860,28 @@ static void do_combatspell(troop at) int fumblechance = 0; order *ord; int sl; - const struct locale *lang = caster->faction->locale; + const struct locale *lang = mage->faction->locale; - sp = get_combatspell(caster, 1); + sp = get_combatspell(mage, 1); if (sp == NULL) { fi->magic = 0; /* Hat keinen Kampfzauber, k�mpft nichtmagisch weiter */ return; } ord = create_order(K_CAST, lang, "'%s'", spell_name(sp, lang)); - if (!cancast(caster, sp, 1, 1, ord)) { + if (!cancast(mage, sp, 1, 1, ord)) { fi->magic = 0; /* Kann nicht mehr Zaubern, k�mpft nichtmagisch weiter */ return; } - level = eff_spelllevel(caster, sp, fi->magic, 1); - sl = get_combatspelllevel(caster, 1); + level = eff_spelllevel(mage, mage, sp, fi->magic, 1); + sl = get_combatspelllevel(mage, 1); if (sl > 0 && sl < level) { level = sl; } - if (fumble(r, caster, sp, level)) { - report_failed_spell(b, caster, sp); - pay_spell(caster, sp, level, 1); + if (fumble(r, mage, sp, level)) { + report_failed_spell(b, mage, sp); + pay_spell(mage, NULL, sp, level, 1); return; } @@ -1822,16 +1897,16 @@ static void do_combatspell(troop at) /* Antimagie die Fehlschlag erh�ht */ if (rng_int() % 100 < fumblechance) { - report_failed_spell(b, caster, sp); - pay_spell(caster, sp, level, 1); + report_failed_spell(b, mage, sp); + pay_spell(mage, NULL, sp, level, 1); free_order(ord); return; } - power = spellpower(r, caster, sp, level, ord); + power = spellpower(r, mage, sp, level, ord); free_order(ord); if (power <= 0) { /* Effekt von Antimagie */ - report_failed_spell(b, caster, sp); - pay_spell(caster, sp, level, 1); + report_failed_spell(b, mage, sp); + pay_spell(mage, NULL, sp, level, 1); return; } @@ -1870,7 +1945,7 @@ int skilldiff(troop at, troop dt, int dist) rc_goblin = get_race(RC_GOBLIN); } skdiff += af->person[at.index].attack; - skdiff -= df->person[dt.index].defence; + skdiff -= df->person[dt.index].defense; if (df->person[dt.index].flags & FL_SLEEPING) skdiff += 2; @@ -1999,11 +2074,12 @@ void dazzle(battle * b, troop * td) } td->fighter->person[td->index].flags |= FL_DAZZLED; - td->fighter->person[td->index].defence--; + td->fighter->person[td->index].defense--; } void damage_building(battle * b, building * bldg, int damage_abs) { + assert(bldg); bldg->size = MAX(1, bldg->size - damage_abs); /* Wenn Burg, dann gucken, ob die Leute alle noch in das Geb�ude passen. */ @@ -2165,7 +2241,7 @@ static void attack(battle * b, troop ta, const att * a, int numattack) td.fighter->person[td.index].attack -= 1; } else { - td.fighter->person[td.index].defence -= 1; + td.fighter->person[td.index].defense -= 1; } c--; } @@ -2278,7 +2354,7 @@ static void add_tactics(tactics * ta, fighter * fig, int value) ta->value = value; } -static double horse_fleeing_bonus(const unit * u) +static int horse_fleeing_bonus(const unit * u) { const item_type *it_horse, *it_elvenhorse, *it_charger; int n1 = 0, n2 = 0, n3 = 0; @@ -2301,26 +2377,26 @@ static double horse_fleeing_bonus(const unit * u) } } if (skl >= 5 && n3 >= u->number) - return 0.30; + return 30; if (skl >= 2 && n2 + n3 >= u->number) - return 0.20; + return 20; if (n1 + n2 + n3 >= u->number) - return 0.10; - return 0.0F; + return 10; + return 0; } -double fleechance(unit * u) +static int fleechance(unit * u) { - double p = 0.20; /* Fluchtwahrscheinlichkeit in % */ + int p = flee_chance_base; /* Fluchtwahrscheinlichkeit in % */ /* Einheit u versucht, dem Get�mmel zu entkommen */ - p += (effskill(u, SK_STEALTH, 0) * 0.05); + p += (effskill(u, SK_STEALTH, 0) * flee_chance_skill_bonus); p += horse_fleeing_bonus(u); if (u_race(u) == get_race(RC_HALFLING)) { - p += 0.20; - if (p > 0.9) { - p = 0.9; + p += flee_chance_base; + if (p > flee_chance_max_percent) { + p = flee_chance_max_percent; } } return p; @@ -2568,7 +2644,7 @@ static void aftermath(battle * b) side *s; int dead_players = 0; bfaction *bf; - bool ships_damaged = (bool)(b->turn + (b->has_tactics_turn ? 1 : 0) > 2); /* only used for ship damage! */ + bool ships_damaged = (b->turn + (b->has_tactics_turn ? 1 : 0) > 2); /* only used for ship damage! */ for (s = b->sides; s != b->sides + b->nsides; ++s) { fighter *df; @@ -2619,7 +2695,7 @@ static void aftermath(battle * b) } } snumber += du->number; - if (df->alive == 0) { + if (dead == df->unit->number) { flags = UFL_DEAD; } else if (relevant) { @@ -3036,9 +3112,7 @@ fighter *make_fighter(battle * b, unit * u, side * s1, bool attack) if (fval(u, UFL_ANON_FACTION) != 0) flags |= SIDE_STEALTH; if (!(AllianceAuto() & HELP_FIGHT) && fval(u, UFL_GROUP)) { - const attrib *agroup = a_find(u->attribs, &at_group); - if (agroup != NULL) - g = (const group *)agroup->data.v; + g = get_group(u); } /* Illusionen und Zauber kaempfen nicht */ @@ -3108,7 +3182,7 @@ fighter *make_fighter(battle * b, unit * u, side * s1, bool attack) strongmen = trollbelts(u); if (strongmen > fig->unit->number) strongmen = fig->unit->number; - /* Hitpoints, Attack- und Defence-Boni f�r alle Personen */ + /* Hitpoints, Attack- und Defense-Boni fuer alle Personen */ for (i = 0; i < fig->alive; i++) { assert(i < fig->unit->number); fig->person[i].hp = h; @@ -3150,7 +3224,7 @@ fighter *make_fighter(battle * b, unit * u, side * s1, bool attack) assert(w != WMAX); } assert(w >= 0); - fig->weapons = (weapon *)calloc(sizeof(weapon), (size_t)(w + 1)); + fig->weapons = (weapon *)calloc((size_t)(w + 1), sizeof(weapon)); memcpy(fig->weapons, weapons, (size_t)w * sizeof(weapon)); for (i = 0; i != w; ++i) { @@ -3355,11 +3429,12 @@ int join_battle(battle * b, unit * u, bool attack, fighter ** cp) battle *make_battle(region * r) { - battle *b = (battle *)calloc(1, sizeof(battle)); unit *u; bfaction *bf; building * bld; + battle *b = (battle *)calloc(1, sizeof(battle)); + assert(b); /* Alle Mann raus aus der Burg! */ for (bld = r->buildings; bld != NULL; bld = bld->next) bld->sizeleft = bld->size; @@ -3376,7 +3451,8 @@ battle *make_battle(region * r) break; } if (!bf) { - bf = (bfaction *)calloc(sizeof(bfaction), 1); + bf = (bfaction *)calloc(1, sizeof(bfaction)); + assert(bf); ++b->nfactions; bf->faction = u->faction; bf->next = b->factions; @@ -3400,14 +3476,15 @@ static void free_side(side * si) static void free_fighter(fighter * fig) { + armor **ap = &fig->armors; + while (*ap) { + armor *a = *ap; + *ap = a->next; + free(a); + } while (fig->loot) { i_free(i_remove(&fig->loot, fig->loot)); } - while (fig->armors) { - armor *a = fig->armors; - fig->armors = a->next; - free(a); - } free(fig->person); free(fig->weapons); @@ -3419,13 +3496,14 @@ static void battle_free(battle * b) { assert(b); for (s = b->sides; s != b->sides + b->nsides; ++s) { - fighter *fnext = s->fighters; - while (fnext) { - fighter *fig = fnext; - fnext = fig->next; + fighter **fp = &s->fighters; + while (*fp) { + fighter *fig = *fp; + *fp = fig->next; free_fighter(fig); free(fig); } + s->fighters = NULL; free_side(s); } free(b); @@ -3560,7 +3638,7 @@ static void join_allies(battle * b) * vorgespiegelt wird, und er sich uns gegen�ber nicht zu * erkennen gibt, helfen wir ihm nicht */ if (s->stealthfaction) { - if (!allysfm(s, u->faction, HELP_FSTEALTH)) { + if (!alliedside(s, u->faction, HELP_FSTEALTH)) { continue; } } @@ -3579,17 +3657,6 @@ static void join_allies(battle * b) } if (se == s_end) continue; - /* Wenn die Einheit belagert ist, mu� auch einer der Alliierten belagert sein: */ - if (besieged(u)) { - fighter *ally; - for (ally = s->fighters; ally; ally = ally->next) { - if (besieged(ally->unit)) { - break; - } - } - if (ally == NULL) - continue; - } /* keine Einw�nde, also soll er mitmachen: */ if (c == NULL) { if (!join_battle(b, u, false, &c)) { @@ -3625,17 +3692,13 @@ static void join_allies(battle * b) } for (sa = s + 1; sa != b->sides + b->nsides; ++sa) { - plane *pl = rplane(r); - if (enemy(s, sa)) - continue; - if (friendly(s, sa)) - continue; - if (!alliedgroup(pl, f, sa->faction, f->allies, HELP_FIGHT)) - continue; - if (!alliedgroup(pl, sa->faction, f, sa->faction->allies, HELP_FIGHT)) - continue; - - set_friendly(s, sa); + if (!enemy(s, sa) && !friendly(s, sa)) { + if (alliedfaction(f, sa->faction, HELP_FIGHT)) { + if (alliedfaction(sa->faction, f, HELP_FIGHT)) { + set_friendly(s, sa); + } + } + } } } } @@ -3644,13 +3707,21 @@ static void flee(const troop dt) { fighter *fig = dt.fighter; unit *u = fig->unit; + int fchance = fleechance(u); - fig->run.hp += fig->person[dt.index].hp; - ++fig->run.number; + if (fig->person[dt.index].flags & FL_PANICED) { + fchance += EFFECT_PANIC_SPELL; + } + if (fchance > flee_chance_max_percent) { + fchance = flee_chance_max_percent; + } + if (rng_int() % 100 < fchance) { + fig->run.hp += fig->person[dt.index].hp; + ++fig->run.number; - setguard(u, false); - - kill_troop(dt); + setguard(u, false); + kill_troop(dt); + } } static bool is_calmed(const unit *u, const faction *f) { @@ -3658,7 +3729,7 @@ static bool is_calmed(const unit *u, const faction *f) { while (a && a->type == &at_curse) { curse *c = (curse *)a->data.v; - if (c->type == &ct_calmmonster && curse_geteffect_int(c) == f->subscription) { + if (c->type == &ct_calmmonster && curse_geteffect_int(c) == f->uid) { if (curse_active(c)) { return true; } @@ -3878,7 +3949,6 @@ static void battle_flee(battle * b) for (fig = s->fighters; fig; fig = fig->next) { unit *u = fig->unit; troop dt; - int runners = 0; /* Flucht nicht bei mehr als 600 HP. Damit Wyrme t�tbar bleiben. */ int runhp = (int)(0.9 + unit_max_hp(u) * hpflee(u->status)); if (runhp > 600) runhp = 600; @@ -3895,7 +3965,6 @@ static void battle_flee(battle * b) dt.fighter = fig; dt.index = fig->alive - fig->removed; while (s->size[SUM_ROW] && dt.index != 0) { - double ispaniced = 0.0; --dt.index; assert(dt.index >= 0 && dt.index < fig->unit->number); assert(fig->person[dt.index].hp > 0); @@ -3920,14 +3989,7 @@ static void battle_flee(battle * b) } continue; } - - if (fig->person[dt.index].flags & FL_PANICED) { - ispaniced = EFFECT_PANIC_SPELL; - } - if (chance(fmin(fleechance(u) + ispaniced, 0.90))) { - ++runners; - flee(dt); - } + flee(dt); } } } @@ -3981,8 +4043,7 @@ void force_leave(region *r, battle *b) { } -void do_battle(region * r) -{ +static void do_battle(region * r) { battle *b = NULL; bool fighting; ship *sh; diff --git a/src/battle.h b/src/battle.h index 48fa7c63a..eb6335bce 100644 --- a/src/battle.h +++ b/src/battle.h @@ -173,9 +173,8 @@ extern "C" { struct person { int hp; /* Trefferpunkte der Personen */ int attack; - int defence; + int defense; int damage; - int damage_rear; int flags; int speed; int reload; @@ -233,7 +232,10 @@ extern "C" { int count_enemies(struct battle *b, const struct fighter *af, int minrow, int maxrow, int select); int natural_armor(struct unit * u); - int calculate_armor(troop dt, const struct weapon_type *dwtype, const struct weapon_type *awtype, union variant *magres); + const struct armor_type *select_armor(struct troop t, bool shield); + struct weapon *select_weapon(const struct troop t, bool attacking, bool ismissile); + int calculate_armor(troop dt, const struct weapon_type *dwtype, const struct weapon_type *awtype, const struct armor_type *armor, const struct armor_type *shield, bool magic); + int apply_resistance(int damage, struct troop dt, const struct weapon_type *dwtype, const struct armor_type *armor, const struct armor_type *shield, bool magic); bool terminate(troop dt, troop at, int type, const char *damage, bool missile); void message_all(battle * b, struct message *m); diff --git a/src/battle.test.c b/src/battle.test.c index 7c7012e77..92a26e692 100644 --- a/src/battle.test.c +++ b/src/battle.test.c @@ -2,6 +2,7 @@ #include "battle.h" +#include "guard.h" #include "reports.h" #include "skill.h" @@ -10,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -17,7 +19,9 @@ #include +#include #include +#include "util/keyword.h" #include #include #include @@ -31,6 +35,21 @@ #include "tests.h" +static void setup_messages(void) { + mt_create_va(mt_new("start_battle", NULL), "factions:string", MT_NEW_END); + mt_create_va(mt_new("para_army_index", NULL), "index:int", "name:string", MT_NEW_END); + mt_create_va(mt_new("battle_msg", NULL), "string:string", MT_NEW_END); + mt_create_va(mt_new("battle_row", NULL), "row:int", MT_NEW_END); + mt_create_va(mt_new("para_lineup_battle", NULL), "turn:int", MT_NEW_END); + mt_create_va(mt_new("para_after_battle", NULL), MT_NEW_END); + mt_create_va(mt_new("army_report", NULL), + "index:int", "abbrev:string", "dead:int", "fled:int", "survived:int", + MT_NEW_END); + mt_create_va(mt_new("casualties", NULL), + "unit:unit", "runto:region", "run:int", "alive:int", "fallen:int", + MT_NEW_END); +} + static void test_make_fighter(CuTest * tc) { unit *au; @@ -59,7 +78,7 @@ static void test_make_fighter(CuTest * tc) af = make_fighter(b, au, as, false); CuAssertIntEquals(tc, 1, b->nfighters); - CuAssertPtrEquals(tc, 0, af->building); + CuAssertPtrEquals(tc, NULL, af->building); CuAssertPtrEquals(tc, as, af->side); CuAssertIntEquals(tc, 0, af->run.hp); CuAssertIntEquals(tc, ST_BEHIND, af->status); @@ -197,7 +216,7 @@ static void test_defenders_get_building_bonus(CuTest * tc) af = make_fighter(b, au, as, true); CuAssertPtrEquals(tc, bld, df->building); - CuAssertPtrEquals(tc, 0, af->building); + CuAssertPtrEquals(tc, NULL, af->building); dt.fighter = df; dt.index = 0; @@ -242,7 +261,7 @@ static void test_attackers_get_no_building_bonus(CuTest * tc) as = make_side(b, au->faction, 0, 0, 0); af = make_fighter(b, au, as, true); - CuAssertPtrEquals(tc, 0, af->building); + CuAssertPtrEquals(tc, NULL, af->building); free_battle(b); test_teardown(); } @@ -279,12 +298,12 @@ static void test_building_bonus_respects_size(CuTest * tc) df = make_fighter(b, du, as, false); CuAssertPtrEquals(tc, bld, af->building); - CuAssertPtrEquals(tc, 0, df->building); + CuAssertPtrEquals(tc, NULL, df->building); free_battle(b); test_teardown(); } -static void test_building_defence_bonus(CuTest * tc) +static void test_building_defense_bonus(CuTest * tc) { building_type * btype; @@ -339,6 +358,16 @@ static void test_natural_armor(CuTest * tc) test_teardown(); } +static int test_armor(troop dt, weapon_type *awtype, bool magic) { + return calculate_armor(dt, 0, awtype, select_armor(dt, false), select_armor(dt, true), magic); +} + +static int test_resistance(troop dt) { + return apply_resistance(1000, dt, + select_weapon(dt, false, true) ? select_weapon(dt, false, true)->type : 0, + select_armor(dt, false), select_armor(dt, true), true); +} + static void test_calculate_armor(CuTest * tc) { troop dt; @@ -349,7 +378,6 @@ static void test_calculate_armor(CuTest * tc) armor_type *ashield, *achain; item_type *ibelt, *ishield, *ichain; race *rc; - variant magres = frac_zero; variant v50p = frac_make(1, 2); test_setup(); @@ -365,18 +393,19 @@ static void test_calculate_armor(CuTest * tc) dt.index = 0; dt.fighter = setup_fighter(&b, du); - CuAssertIntEquals_Msg(tc, "default ac", 0, calculate_armor(dt, 0, 0, &magres)); - CuAssertIntEquals_Msg(tc, "magres unmodified", magres.sa[0], magres.sa[1]); + CuAssertIntEquals_Msg(tc, "default ac", 0, test_armor(dt, 0, false)); + + CuAssertIntEquals_Msg(tc, "magres unmodified", 1000, test_resistance(dt)); free_battle(b); b = NULL; i_change(&du->items, ibelt, 1); dt.fighter = setup_fighter(&b, du); CuAssertIntEquals_Msg(tc, "without natural armor", 0, natural_armor(du)); - CuAssertIntEquals_Msg(tc, "magical armor", 1, calculate_armor(dt, 0, 0, 0)); + CuAssertIntEquals_Msg(tc, "magical armor", 1, test_armor(dt, 0, false)); rc->armor = 2; CuAssertIntEquals_Msg(tc, "with natural armor", 2, natural_armor(du)); - CuAssertIntEquals_Msg(tc, "natural armor", 3, calculate_armor(dt, 0, 0, 0)); + CuAssertIntEquals_Msg(tc, "natural armor", 3, test_armor(dt, 0, false)); rc->armor = 0; free_battle(b); @@ -385,29 +414,30 @@ static void test_calculate_armor(CuTest * tc) i_change(&du->items, ichain, 1); dt.fighter = setup_fighter(&b, du); rc->battle_flags &= ~BF_EQUIPMENT; - CuAssertIntEquals_Msg(tc, "require BF_EQUIPMENT", 1, calculate_armor(dt, 0, 0, 0)); + CuAssertIntEquals_Msg(tc, "require BF_EQUIPMENT", 1, test_armor(dt, 0, false)); free_battle(b); b = NULL; rc->battle_flags |= BF_EQUIPMENT; dt.fighter = setup_fighter(&b, du); - CuAssertIntEquals_Msg(tc, "stack equipment rc", 5, calculate_armor(dt, 0, 0, 0)); + CuAssertIntEquals_Msg(tc, "stack equipment rc", 5, test_armor(dt, 0, false)); rc->armor = 2; - CuAssertIntEquals_Msg(tc, "natural armor adds 50%", 6, calculate_armor(dt, 0, 0, 0)); + CuAssertIntEquals_Msg(tc, "natural armor adds 50%", 6, test_armor(dt, 0, false)); wtype->flags = WTF_NONE; - CuAssertIntEquals_Msg(tc, "regular weapon has no effect", 6, calculate_armor(dt, 0, wtype, 0)); + CuAssertIntEquals_Msg(tc, "regular weapon has no effect", 6, test_armor(dt, wtype, false)); wtype->flags = WTF_ARMORPIERCING; - CuAssertIntEquals_Msg(tc, "armor piercing weapon", 3, calculate_armor(dt, 0, wtype, 0)); + CuAssertIntEquals_Msg(tc, "armor piercing weapon", 3, test_armor(dt, wtype, false)); wtype->flags = WTF_NONE; - CuAssertIntEquals_Msg(tc, "magical attack", 3, calculate_armor(dt, 0, 0, &magres)); - CuAssertIntEquals_Msg(tc, "magres unmodified", magres.sa[1], magres.sa[0]); + CuAssertIntEquals_Msg(tc, "magical attack", 3, test_armor(dt, wtype, true)); + CuAssertIntEquals_Msg(tc, "magres unmodified", 1000, + test_resistance(dt)); ashield->flags |= ATF_LAEN; achain->flags |= ATF_LAEN; - magres = frac_one; - CuAssertIntEquals_Msg(tc, "laen armor", 3, calculate_armor(dt, 0, 0, &magres)); - CuAssertIntEquals_Msg(tc, "laen magres bonus", 4, magres.sa[1]); + + CuAssertIntEquals_Msg(tc, "laen armor", 3, test_armor(dt, wtype, true)); + CuAssertIntEquals_Msg(tc, "laen magres bonus", 250, test_resistance(dt)); free_battle(b); test_teardown(); } @@ -437,15 +467,17 @@ static void test_magic_resistance(CuTest *tc) i_change(&du->items, ishield, 1); dt.fighter = setup_fighter(&b, du); - calculate_armor(dt, 0, 0, &magres); - CuAssertIntEquals_Msg(tc, "no magres reduction", magres.sa[1], magres.sa[0]); + CuAssertIntEquals_Msg(tc, "no magres reduction", 1000, test_resistance(dt)); magres = magic_resistance(du); CuAssertIntEquals_Msg(tc, "no magres reduction", 0, magres.sa[0]); ashield->flags |= ATF_LAEN; ashield->magres = v10p; - calculate_armor(dt, 0, 0, &magres); - CuAssert(tc, "laen reduction => 10%%", frac_equal(frac_make(9, 10), magres)); + CuAssertIntEquals_Msg(tc, "laen reduction => 10%%", 900, test_resistance(dt)); + CuAssertIntEquals_Msg(tc, "no magic, no resistance", 1000, + apply_resistance(1000, dt, + select_weapon(dt, false, true) ? select_weapon(dt, false, true)->type : 0, + select_armor(dt, false), select_armor(dt, true), false)); free_battle(b); b = NULL; @@ -455,8 +487,7 @@ static void test_magic_resistance(CuTest *tc) ashield->flags |= ATF_LAEN; ashield->magres = v10p; dt.fighter = setup_fighter(&b, du); - calculate_armor(dt, 0, 0, &magres); - CuAssert(tc, "2x laen reduction => 81%%", frac_equal(frac_make(81, 100), magres)); + CuAssertIntEquals_Msg(tc, "2x laen reduction => 81%%", 810, test_resistance(dt)); free_battle(b); b = NULL; @@ -464,21 +495,18 @@ static void test_magic_resistance(CuTest *tc) i_change(&du->items, ichain, -1); set_level(du, SK_MAGIC, 2); dt.fighter = setup_fighter(&b, du); - calculate_armor(dt, 0, 0, &magres); - CuAssert(tc, "skill reduction => 90%%", frac_equal(magres, frac_make(9, 10))); + CuAssertIntEquals_Msg(tc, "skill reduction => 90%%", 900, test_resistance(dt)); magres = magic_resistance(du); CuAssert(tc, "skill reduction", frac_equal(magres, v10p)); rc->magres = v50p; /* percentage, gets added to skill bonus */ - calculate_armor(dt, 0, 0, &magres); - CuAssert(tc, "race reduction => 40%%", frac_equal(magres, frac_make(4, 10))); + CuAssertIntEquals_Msg(tc, "race reduction => 40%%", 400, test_resistance(dt)); magres = magic_resistance(du); CuAssert(tc, "race bonus => 60%%", frac_equal(magres, frac_make(60, 100))); rc->magres = frac_make(15, 10); /* 150% resistance should not cause negative damage multiplier */ magres = magic_resistance(du); CuAssert(tc, "magic resistance is never > 0.9", frac_equal(magres, frac_make(9, 10))); - calculate_armor(dt, 0, 0, &magres); - CuAssert(tc, "damage reduction is never < 0.1", frac_equal(magres, frac_make(1, 10))); + CuAssertIntEquals_Msg(tc, "damage reduction is never < 0.1", 100, test_resistance(dt)); free_battle(b); test_teardown(); @@ -513,12 +541,12 @@ static void test_projectile_armor(CuTest * tc) dt.fighter = setup_fighter(&b, du); wtype->flags = WTF_MISSILE; achain->projectile = 1.0; - CuAssertIntEquals_Msg(tc, "projectile armor", -1, calculate_armor(dt, 0, wtype, 0)); + CuAssertIntEquals_Msg(tc, "projectile armor", -1, test_armor(dt, wtype, false)); achain->projectile = 0.0; ashield->projectile = 1.0; - CuAssertIntEquals_Msg(tc, "projectile shield", -1, calculate_armor(dt, 0, wtype, 0)); + CuAssertIntEquals_Msg(tc, "projectile shield", -1, test_armor(dt, wtype, false)); wtype->flags = WTF_NONE; - CuAssertIntEquals_Msg(tc, "no projectiles", 4, calculate_armor(dt, 0, wtype, 0)); + CuAssertIntEquals_Msg(tc, "no projectiles", 4, test_armor(dt, wtype, false)); free_battle(b); test_teardown(); } @@ -542,7 +570,7 @@ static void test_battle_skilldiff(CuTest *tc) CuAssertIntEquals(tc, 0, skilldiff(ta, td, 0)); ta.fighter->person[0].attack = 2; - td.fighter->person[0].defence = 1; + td.fighter->person[0].defense = 1; CuAssertIntEquals(tc, 1, skilldiff(ta, td, 0)); td.fighter->person[0].flags |= FL_SLEEPING; @@ -556,6 +584,38 @@ static void test_battle_skilldiff(CuTest *tc) test_teardown(); } +static void test_terminate(CuTest * tc) +{ + troop at, dt; + battle *b = NULL; + region *r; + unit *au, *du; + race *rc; + + test_setup(); + r = test_create_region(0, 0, NULL); + + rc = test_create_race("human"); + au = test_create_unit(test_create_faction(rc), r); + du = test_create_unit(test_create_faction(rc), r); + dt.index = 0; + at.index = 0; + + at.fighter = setup_fighter(&b, au); + dt.fighter = setup_fighter(&b, du); + + CuAssertIntEquals_Msg(tc, "not killed", 0, terminate(dt, at, AT_STANDARD, "1d1", false)); + b = NULL; + at.fighter = setup_fighter(&b, au); + dt.fighter = setup_fighter(&b, du); + CuAssertIntEquals_Msg(tc, "killed", 1, terminate(dt, at, AT_STANDARD, "100d1", false)); + CuAssertIntEquals_Msg(tc, "number", 0, dt.fighter->person[0].hp); + + free_battle(b); + test_teardown(); +} + + static void test_battle_report_one(CuTest *tc) { battle * b = NULL; @@ -566,7 +626,7 @@ static void test_battle_report_one(CuTest *tc) fighter *fig; test_setup(); - mt_create_va(mt_new("start_battle", NULL), "factions:string", MT_NEW_END); + setup_messages(); r = test_create_plain(0, 0); u1 = test_create_unit(test_create_faction(NULL), r); u2 = test_create_unit(test_create_faction(NULL), r); @@ -597,7 +657,7 @@ static void test_battle_report_two(CuTest *tc) test_setup(); lang = test_create_locale(); locale_setstring(lang, "and", "and"); - mt_create_va(mt_new("start_battle", NULL), "factions:string", MT_NEW_END); + setup_messages(); r = test_create_plain(0, 0); u1 = test_create_unit(test_create_faction(NULL), r); u1->faction->locale = lang; @@ -630,7 +690,7 @@ static void test_battle_report_three(CuTest *tc) test_setup(); lang = test_create_locale(); locale_setstring(lang, "and", "and"); - mt_create_va(mt_new("start_battle", NULL), "factions:string", MT_NEW_END); + setup_messages(); r = test_create_plain(0, 0); u1 = test_create_unit(test_create_faction(NULL), r); u1->faction->locale = lang; @@ -783,12 +843,43 @@ static void test_tactics_chance(CuTest *tc) { test_teardown(); } +static void test_battle_fleeing(CuTest *tc) { + region *r; + unit *u1, *u2; + test_setup(); + setup_messages(); + r = test_create_plain(0, 0); + u1 = test_create_unit(test_create_faction(NULL), r); + u2 = test_create_unit(test_create_faction(NULL), r); + u1->status = ST_FLEE; + u2->status = ST_AGGRO; +#if 0 + setguard(u1, true); + CuAssertIntEquals(tc, UFL_GUARD, (u1->flags & UFL_GUARD)); + CuAssertIntEquals(tc, RF_GUARDED, (r->flags & RF_GUARDED)); +#endif + config_set_int("rules.combat.flee_chance_base", 100); + config_set_int("rules.combat.flee_chance_limit", 100); + unit_addorder(u2, create_order(K_ATTACK, u2->faction->locale, itoa36(u1->no))); + do_battles(); + CuAssertIntEquals(tc, 1, u1->number); + CuAssertIntEquals(tc, 1, u2->number); +#if 0 + CuAssertIntEquals(tc, 0, (u1->flags & UFL_GUARD)); + CuAssertIntEquals(tc, 0, (r->flags & RF_GUARDED)); +#endif + CuAssertIntEquals(tc, UFL_LONGACTION, (u1->flags & UFL_LONGACTION)); + CuAssertIntEquals(tc, UFL_LONGACTION | UFL_NOTMOVING, (u2->flags & (UFL_LONGACTION | UFL_NOTMOVING))); + test_teardown(); +} + CuSuite *get_battle_suite(void) { CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_make_fighter); SUITE_ADD_TEST(suite, test_select_weapon_restricted); SUITE_ADD_TEST(suite, test_select_armor); + SUITE_ADD_TEST(suite, test_battle_fleeing); SUITE_ADD_TEST(suite, test_battle_skilldiff); SUITE_ADD_TEST(suite, test_battle_skilldiff_building); SUITE_ADD_TEST(suite, test_battle_report_one); @@ -797,12 +888,13 @@ CuSuite *get_battle_suite(void) SUITE_ADD_TEST(suite, test_defenders_get_building_bonus); SUITE_ADD_TEST(suite, test_attackers_get_no_building_bonus); SUITE_ADD_TEST(suite, test_building_bonus_respects_size); - SUITE_ADD_TEST(suite, test_building_defence_bonus); + SUITE_ADD_TEST(suite, test_building_defense_bonus); SUITE_ADD_TEST(suite, test_calculate_armor); SUITE_ADD_TEST(suite, test_natural_armor); SUITE_ADD_TEST(suite, test_magic_resistance); SUITE_ADD_TEST(suite, test_projectile_armor); SUITE_ADD_TEST(suite, test_tactics_chance); + SUITE_ADD_TEST(suite, test_terminate); DISABLE_TEST(suite, test_drain_exp); return suite; } diff --git a/src/bind_building.c b/src/bind_building.c index 9e39a54a5..93576ed3b 100644 --- a/src/bind_building.c +++ b/src/bind_building.c @@ -5,7 +5,6 @@ #include "bind_building.h" #include "bind_unit.h" -#include #include #include #include @@ -15,9 +14,12 @@ #include #include +#include +#include #include + +#include #include -#include int tolua_buildinglist_next(lua_State * L) { diff --git a/src/bind_config.c b/src/bind_config.c index 2d4086ccf..31ffcc287 100644 --- a/src/bind_config.c +++ b/src/bind_config.c @@ -5,17 +5,15 @@ #include "bind_config.h" #include "jsonconf.h" +#include "magic.h" #include #include #include #include #include -#include -#include #include -#include #include #include #include diff --git a/src/bind_eressea.c b/src/bind_eressea.c index 11c03898d..f76d0a903 100755 --- a/src/bind_eressea.c +++ b/src/bind_eressea.c @@ -3,8 +3,6 @@ #endif #include "bind_eressea.h" -#include - #include "json.h" #include "orderfile.h" @@ -14,15 +12,17 @@ #include #include +#include #include +#include #include void eressea_free_game(void) { free_gamedata(); init_resources(); - init_locales(); + init_locales(init_locale); } int eressea_read_game(const char * filename) { @@ -35,7 +35,17 @@ int eressea_write_game(const char * filename) { } int eressea_read_orders(const char * filename) { - return readorders(filename); + FILE * F = fopen(filename, "r"); + int result; + + if (!F) { + perror(filename); + return -1; + } + log_info("reading orders from %s", filename); + result = parseorders(F); + fclose(F); + return result; } int eressea_export_json(const char * filename, int flags) { diff --git a/src/bind_faction.c b/src/bind_faction.c index ac797093d..9cc6bdd97 100644 --- a/src/bind_faction.c +++ b/src/bind_faction.c @@ -17,47 +17,32 @@ without prior permission by the authors of Eressea. #include "bind_faction.h" #include "bind_unit.h" #include "bindings.h" -#include "helpers.h" +#include "magic.h" #include #include #include #include -#include #include #include #include #include -#include -#include +#include "kernel/types.h" #include #include #include #include +#include #include +#include "attributes/key.h" + +#include +#include #include #include #include -#include - -typedef struct helpmode { - const char *name; - int status; -} helpmode; - -static helpmode helpmodes[] = { - { "all", HELP_ALL }, - { "money", HELP_MONEY }, - { "fight", HELP_FIGHT }, - { "observe", HELP_OBSERVE }, - { "give", HELP_GIVE }, - { "guard", HELP_GUARD }, - { "stealth", HELP_FSTEALTH }, - { "travel", HELP_TRAVEL }, - { NULL, 0 } -}; int tolua_factionlist_next(lua_State * L) { @@ -74,7 +59,7 @@ int tolua_factionlist_next(lua_State * L) static int tolua_faction_get_units(lua_State * L) { - faction *self = (faction *)tolua_tousertype(L, 1, 0); + faction *self = (faction *)tolua_tousertype(L, 1, NULL); unit **unit_ptr = (unit **)lua_newuserdata(L, sizeof(unit *)); luaL_getmetatable(L, TOLUA_CAST "unit"); @@ -88,8 +73,8 @@ static int tolua_faction_get_units(lua_State * L) int tolua_faction_add_item(lua_State * L) { - faction *self = (faction *)tolua_tousertype(L, 1, 0); - const char *iname = tolua_tostring(L, 2, 0); + faction *self = (faction *)tolua_tousertype(L, 1, NULL); + const char *iname = tolua_tostring(L, 2, NULL); int number = (int)tolua_tonumber(L, 3, 0); int result = -1; @@ -106,35 +91,35 @@ int tolua_faction_add_item(lua_State * L) static int tolua_faction_get_maxheroes(lua_State * L) { - faction *self = (faction *)tolua_tousertype(L, 1, 0); + faction *self = (faction *)tolua_tousertype(L, 1, NULL); lua_pushinteger(L, maxheroes(self)); return 1; } static int tolua_faction_get_heroes(lua_State * L) { - faction *self = (faction *)tolua_tousertype(L, 1, 0); + faction *self = (faction *)tolua_tousertype(L, 1, NULL); lua_pushinteger(L, countheroes(self)); return 1; } static int tolua_faction_get_score(lua_State * L) { - faction *self = (faction *)tolua_tousertype(L, 1, 0); + faction *self = (faction *)tolua_tousertype(L, 1, NULL); lua_pushnumber(L, (lua_Number)self->score); return 1; } static int tolua_faction_get_id(lua_State * L) { - faction *self = (faction *)tolua_tousertype(L, 1, 0); + faction *self = (faction *)tolua_tousertype(L, 1, NULL); lua_pushinteger(L, self->no); return 1; } static int tolua_faction_set_id(lua_State * L) { - faction *self = (faction *)tolua_tousertype(L, 1, 0); + faction *self = (faction *)tolua_tousertype(L, 1, NULL); int id = (int)tolua_tonumber(L, 2, 0); if (findfaction(id) == NULL) { renumber_faction(self, id); @@ -148,15 +133,15 @@ static int tolua_faction_set_id(lua_State * L) static int tolua_faction_get_magic(lua_State * L) { - faction *self = (faction *)tolua_tousertype(L, 1, 0); + faction *self = (faction *)tolua_tousertype(L, 1, NULL); lua_pushstring(L, magic_school[self->magiegebiet]); return 1; } static int tolua_faction_set_magic(lua_State * L) { - faction *self = (faction *)tolua_tousertype(L, 1, 0); - const char *type = tolua_tostring(L, 2, 0); + faction *self = (faction *)tolua_tousertype(L, 1, NULL); + const char *type = tolua_tostring(L, 2, NULL); int mtype; for (mtype = 0; mtype != MAXMAGIETYP; ++mtype) { @@ -170,14 +155,14 @@ static int tolua_faction_set_magic(lua_State * L) static int tolua_faction_get_age(lua_State * L) { - faction *self = (faction *)tolua_tousertype(L, 1, 0); + faction *self = (faction *)tolua_tousertype(L, 1, NULL); lua_pushinteger(L, self->age); return 1; } static int tolua_faction_set_age(lua_State * L) { - faction *self = (faction *)tolua_tousertype(L, 1, 0); + faction *self = (faction *)tolua_tousertype(L, 1, NULL); int age = (int)tolua_tonumber(L, 2, 0); self->age = age; return 0; @@ -185,14 +170,14 @@ static int tolua_faction_set_age(lua_State * L) static int tolua_faction_get_flags(lua_State * L) { - faction *self = (faction *)tolua_tousertype(L, 1, 0); + faction *self = (faction *)tolua_tousertype(L, 1, NULL); lua_pushinteger(L, self->flags); return 1; } static int tolua_faction_set_flags(lua_State * L) { - faction *self = (faction *)tolua_tousertype(L, 1, 0); + faction *self = (faction *)tolua_tousertype(L, 1, NULL); int flags = (int)tolua_tonumber(L, 2, self->flags); self->flags = flags; return 1; @@ -200,14 +185,14 @@ static int tolua_faction_set_flags(lua_State * L) static int tolua_faction_get_options(lua_State * L) { - faction *self = (faction *)tolua_tousertype(L, 1, 0); + faction *self = (faction *)tolua_tousertype(L, 1, NULL); lua_pushinteger(L, self->options); return 1; } static int tolua_faction_set_options(lua_State * L) { - faction *self = (faction *)tolua_tousertype(L, 1, 0); + faction *self = (faction *)tolua_tousertype(L, 1, NULL); int options = (int)tolua_tonumber(L, 2, self->options); self->options = options; return 1; @@ -215,14 +200,14 @@ static int tolua_faction_set_options(lua_State * L) static int tolua_faction_get_lastturn(lua_State * L) { - faction *self = (faction *)tolua_tousertype(L, 1, 0); + faction *self = (faction *)tolua_tousertype(L, 1, NULL); lua_pushinteger(L, self->lastorders); return 1; } static int tolua_faction_set_lastturn(lua_State * L) { - faction *self = (faction *)tolua_tousertype(L, 1, 0); + faction *self = (faction *)tolua_tousertype(L, 1, NULL); if (self) { self->lastorders = (int)tolua_tonumber(L, 2, self->lastorders); } @@ -231,7 +216,7 @@ static int tolua_faction_set_lastturn(lua_State * L) static int tolua_faction_renumber(lua_State * L) { - faction *self = (faction *)tolua_tousertype(L, 1, 0); + faction *self = (faction *)tolua_tousertype(L, 1, NULL); int no = (int)tolua_tonumber(L, 2, 0); renumber_faction(self, no); @@ -240,8 +225,8 @@ static int tolua_faction_renumber(lua_State * L) static int tolua_faction_addnotice(lua_State * L) { - faction *self = (faction *)tolua_tousertype(L, 1, 0); - const char *str = tolua_tostring(L, 2, 0); + faction *self = (faction *)tolua_tousertype(L, 1, NULL); + const char *str = tolua_tostring(L, 2, NULL); addmessage(NULL, self, str, MSG_MESSAGE, ML_IMPORTANT); return 0; @@ -249,19 +234,22 @@ static int tolua_faction_addnotice(lua_State * L) static int tolua_faction_getkey(lua_State * L) { - faction *self = (faction *)tolua_tousertype(L, 1, 0); - const char *name = tolua_tostring(L, 2, 0); + faction *self = (faction *)tolua_tousertype(L, 1, NULL); + const char *name = tolua_tostring(L, 2, NULL); int flag = atoi36(name); - - lua_pushinteger(L, key_get(self->attribs, flag)); - return 1; + int value = key_get(self->attribs, flag); + if (value != 0) { + lua_pushinteger(L, value); + return 1; + } + return 0; } static int tolua_faction_setkey(lua_State * L) { - faction *self = (faction *)tolua_tousertype(L, 1, 0); - const char *name = tolua_tostring(L, 2, 0); - int value = (int)tolua_tonumber(L, 3, 0); + faction *self = (faction *)tolua_tousertype(L, 1, NULL); + const char *name = tolua_tostring(L, 2, NULL); + int value = (int)tolua_tonumber(L, 3, 1); int flag = atoi36(name); if (value) { @@ -275,7 +263,7 @@ static int tolua_faction_setkey(lua_State * L) static int tolua_faction_get_messages(lua_State * L) { - faction *self = (faction *)tolua_tousertype(L, 1, 0); + faction *self = (faction *)tolua_tousertype(L, 1, NULL); int i = 1; mlist *ml; if (!self->msgs) { @@ -291,8 +279,8 @@ static int tolua_faction_get_messages(lua_State * L) } 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); + faction *self = (faction *)tolua_tousertype(L, 1, NULL); + const char *str = tolua_tostring(L, 2, NULL); int n = 0; if (self->msgs) { mlist * ml = self->msgs->begin; @@ -307,53 +295,10 @@ static int tolua_faction_count_msg_type(lua_State *L) { return 1; } -static int tolua_faction_get_policy(lua_State * L) -{ - faction *self = (faction *)tolua_tousertype(L, 1, 0); - faction *other = (faction *)tolua_tousertype(L, 2, 0); - const char *policy = tolua_tostring(L, 3, 0); - - int result = 0, mode; - for (mode = 0; helpmodes[mode].name != NULL; ++mode) { - if (strcmp(policy, helpmodes[mode].name) == 0) { - result = get_alliance(self, other) & mode; - break; - } - } - - lua_pushinteger(L, result); - return 1; -} - -static int tolua_faction_set_policy(lua_State * L) -{ - faction *self = (faction *)tolua_tousertype(L, 1, 0); - faction *other = (faction *)tolua_tousertype(L, 2, 0); - const char *policy = tolua_tostring(L, 3, 0); - int value = tolua_toboolean(L, 4, 0); - - int mode; - for (mode = 0; helpmodes[mode].name != NULL; ++mode) { - if (strcmp(policy, helpmodes[mode].name) == 0) { - if (value) { - set_alliance(self, other, get_alliance(self, - other) | helpmodes[mode].status); - } - else { - set_alliance(self, other, get_alliance(self, - other) & ~helpmodes[mode].status); - } - break; - } - } - - return 0; -} - static int tolua_faction_normalize(lua_State * L) { - faction *f = (faction *)tolua_tousertype(L, 1, 0); - region *r = (region *)tolua_tousertype(L, 2, 0); + faction *f = (faction *)tolua_tousertype(L, 1, NULL); + region *r = (region *)tolua_tousertype(L, 2, NULL); if (r) { plane *pl = rplane(r); int nx = r->x, ny = r->y; @@ -368,8 +313,8 @@ static int tolua_faction_normalize(lua_State * L) static int tolua_faction_set_origin(lua_State * L) { - faction *f = (faction *)tolua_tousertype(L, 1, 0); - region *r = (region *)tolua_tousertype(L, 2, 0); + faction *f = (faction *)tolua_tousertype(L, 1, NULL); + region *r = (region *)tolua_tousertype(L, 2, NULL); plane *pl = rplane(r); int id = pl ? pl->id : 0; @@ -379,21 +324,9 @@ static int tolua_faction_set_origin(lua_State * L) static int tolua_faction_get_origin(lua_State * L) { - faction *self = (faction *)tolua_tousertype(L, 1, 0); - - ursprung *origin = self->ursprung; - int x, y; - while (origin != NULL && origin->id != 0) { - origin = origin->next; - } - if (origin) { - x = origin->x; - y = origin->y; - } - else { - x = 0; - y = 0; - } + faction *self = (faction *)tolua_tousertype(L, 1, NULL); + int x = 0, y = 0; + faction_getorigin(self, 0, &x, &y); lua_pushinteger(L, x); lua_pushinteger(L, y); @@ -402,7 +335,7 @@ static int tolua_faction_get_origin(lua_State * L) static int tolua_faction_destroy(lua_State * L) { - faction **fp, *f = (faction *)tolua_tousertype(L, 1, 0); + faction **fp, *f = (faction *)tolua_tousertype(L, 1, NULL); /* TODO: this loop is slow af, but what can we do? */ for (fp = &factions; *fp; fp = &(*fp)->next) { if (*fp == f) { @@ -423,14 +356,14 @@ static int tolua_faction_get(lua_State * L) static int tolua_faction_create(lua_State * L) { - const char *racename = tolua_tostring(L, 1, 0); - const char *email = tolua_tostring(L, 2, 0); - const char *lang = tolua_tostring(L, 3, 0); + const char *racename = tolua_tostring(L, 1, NULL); + const char *email = tolua_tostring(L, 2, NULL); + const char *lang = tolua_tostring(L, 3, NULL); struct locale *loc = lang ? get_locale(lang) : default_locale; faction *f = NULL; const struct race *frace = rc_find(racename ? racename : "human"); if (frace != NULL) { - f = addfaction(email, NULL, frace, loc, 0); + f = addfaction(email, NULL, frace, loc); } if (!f) { log_error("cannot create %s faction for %s, unknown race.", racename, email); @@ -441,44 +374,44 @@ static int tolua_faction_create(lua_State * L) static int tolua_faction_get_password(lua_State * L) { - faction *self = (faction *)tolua_tousertype(L, 1, 0); - tolua_pushstring(L, self->_password); + faction *self = (faction *)tolua_tousertype(L, 1, NULL); + tolua_pushstring(L, faction_getpassword(self)); return 1; } static int tolua_faction_set_password(lua_State * L) { - faction *self = (faction *)tolua_tousertype(L, 1, 0); - const char * passw = tolua_tostring(L, 2, 0); - faction_setpassword(self, password_encode(passw, PASSWORD_DEFAULT)); + faction *self = (faction *)tolua_tousertype(L, 1, NULL); + const char * passw = tolua_tostring(L, 2, NULL); + faction_setpassword(self, password_hash(passw, PASSWORD_DEFAULT)); return 0; } static int tolua_faction_get_email(lua_State * L) { - faction *self = (faction *)tolua_tousertype(L, 1, 0); + faction *self = (faction *)tolua_tousertype(L, 1, NULL); tolua_pushstring(L, faction_getemail(self)); return 1; } static int tolua_faction_set_email(lua_State * L) { - faction *self = (faction *)tolua_tousertype(L, 1, 0); - faction_setemail(self, tolua_tostring(L, 2, 0)); + faction *self = (faction *)tolua_tousertype(L, 1, NULL); + faction_setemail(self, tolua_tostring(L, 2, NULL)); return 0; } static int tolua_faction_get_locale(lua_State * L) { - faction *self = (faction *)tolua_tousertype(L, 1, 0); + faction *self = (faction *)tolua_tousertype(L, 1, NULL); tolua_pushstring(L, locale_name(self->locale)); return 1; } static int tolua_faction_set_locale(lua_State * L) { - faction *self = (faction *)tolua_tousertype(L, 1, 0); - const char *name = tolua_tostring(L, 2, 0); + faction *self = (faction *)tolua_tousertype(L, 1, NULL); + const char *name = tolua_tostring(L, 2, NULL); const struct locale *loc = get_locale(name); if (loc) { self->locale = loc; @@ -492,15 +425,15 @@ static int tolua_faction_set_locale(lua_State * L) static int tolua_faction_get_race(lua_State * L) { - faction *self = (faction *)tolua_tousertype(L, 1, 0); + faction *self = (faction *)tolua_tousertype(L, 1, NULL); tolua_pushstring(L, self->race->_name); return 1; } static int tolua_faction_set_race(lua_State * L) { - faction *self = (faction *)tolua_tousertype(L, 1, 0); - const char *name = tolua_tostring(L, 2, 0); + faction *self = (faction *)tolua_tousertype(L, 1, NULL); + const char *name = tolua_tostring(L, 2, NULL); const race *rc = rc_find(name); if (rc != NULL) { self->race = rc; @@ -511,57 +444,57 @@ static int tolua_faction_set_race(lua_State * L) static int tolua_faction_get_name(lua_State * L) { - faction *self = (faction *)tolua_tousertype(L, 1, 0); + faction *self = (faction *)tolua_tousertype(L, 1, NULL); tolua_pushstring(L, faction_getname(self)); return 1; } static int tolua_faction_set_name(lua_State * L) { - faction *self = (faction *)tolua_tousertype(L, 1, 0); - faction_setname(self, tolua_tostring(L, 2, 0)); + faction *self = (faction *)tolua_tousertype(L, 1, NULL); + faction_setname(self, tolua_tostring(L, 2, NULL)); return 0; } static int tolua_faction_get_uid(lua_State * L) { - faction *f = (faction *)tolua_tousertype(L, 1, 0); - lua_pushinteger(L, f->subscription); + faction *f = (faction *)tolua_tousertype(L, 1, NULL); + lua_pushinteger(L, f->uid); return 1; } static int tolua_faction_set_uid(lua_State * L) { - faction *f = (faction *)tolua_tousertype(L, 1, 0); - f->subscription = (int)tolua_tonumber(L, 2, 0); + faction *f = (faction *)tolua_tousertype(L, 1, NULL); + f->uid = (int)tolua_tonumber(L, 2, 0); return 0; } static int tolua_faction_get_info(lua_State * L) { - faction *self = (faction *)tolua_tousertype(L, 1, 0); + faction *self = (faction *)tolua_tousertype(L, 1, NULL); tolua_pushstring(L, faction_getbanner(self)); return 1; } static int tolua_faction_set_info(lua_State * L) { - faction *self = (faction *)tolua_tousertype(L, 1, 0); - faction_setbanner(self, tolua_tostring(L, 2, 0)); + faction *self = (faction *)tolua_tousertype(L, 1, NULL); + faction_setbanner(self, tolua_tostring(L, 2, NULL)); return 0; } static int tolua_faction_get_alliance(lua_State * L) { - faction *self = (faction *)tolua_tousertype(L, 1, 0); + faction *self = (faction *)tolua_tousertype(L, 1, NULL); tolua_pushusertype(L, f_get_alliance(self), TOLUA_CAST "alliance"); return 1; } static int tolua_faction_set_alliance(lua_State * L) { - struct faction *self = (struct faction *)tolua_tousertype(L, 1, 0); - struct alliance *alli = (struct alliance *) tolua_tousertype(L, 2, 0); + struct faction *self = (struct faction *)tolua_tousertype(L, 1, NULL); + struct alliance *alli = (struct alliance *) tolua_tousertype(L, 2, NULL); setalliance(self, alli); @@ -570,7 +503,7 @@ static int tolua_faction_set_alliance(lua_State * L) static int tolua_faction_get_items(lua_State * L) { - faction *self = (faction *)tolua_tousertype(L, 1, 0); + faction *self = (faction *)tolua_tousertype(L, 1, NULL); item **item_ptr = (item **)lua_newuserdata(L, sizeof(item *)); luaL_getmetatable(L, TOLUA_CAST "item"); @@ -585,7 +518,7 @@ static int tolua_faction_get_items(lua_State * L) static int tolua_faction_tostring(lua_State * L) { - faction *self = (faction *)tolua_tousertype(L, 1, 0); + faction *self = (faction *)tolua_tousertype(L, 1, NULL); lua_pushstring(L, factionname(self)); return 1; } @@ -642,8 +575,6 @@ void tolua_faction_open(lua_State * L) tolua_variable(L, TOLUA_CAST "lastturn", tolua_faction_get_lastturn, tolua_faction_set_lastturn); - tolua_function(L, TOLUA_CAST "set_policy", tolua_faction_set_policy); - tolua_function(L, TOLUA_CAST "get_policy", tolua_faction_get_policy); tolua_function(L, TOLUA_CAST "get_origin", tolua_faction_get_origin); tolua_function(L, TOLUA_CAST "set_origin", tolua_faction_set_origin); tolua_function(L, TOLUA_CAST "normalize", tolua_faction_normalize); diff --git a/src/bind_gmtool.c b/src/bind_gmtool.c index 5c08f6e2c..d0a023a5b 100644 --- a/src/bind_gmtool.c +++ b/src/bind_gmtool.c @@ -14,6 +14,8 @@ #include #include +#include +#include #include #include diff --git a/src/bind_message.c b/src/bind_message.c index 8eee85bc1..bf82ddd02 100644 --- a/src/bind_message.c +++ b/src/bind_message.c @@ -16,14 +16,18 @@ #include #include #include +#include /* lua includes */ +#include #include #include #include #include +struct order; + #define E_OK 0 #define E_INVALID_MESSAGE 1 #define E_INVALID_PARAMETER_NAME 2 diff --git a/src/bind_monsters.c b/src/bind_monsters.c index af630bb41..f9aef4a2a 100644 --- a/src/bind_monsters.c +++ b/src/bind_monsters.c @@ -2,20 +2,19 @@ #include #endif -#include "spells/shipcurse.h" #include "monsters.h" #include #include -#include #include -#include #include #include +#include #include + #include static int tolua_levitate_ship(lua_State * L) @@ -62,7 +61,7 @@ static int tolua_spawn_undead(lua_State * L) return 0; } -void bind_monsters(struct lua_State *L) +void bind_monsters(lua_State *L) { tolua_module(L, NULL, 0); tolua_beginmodule(L, NULL); diff --git a/src/bind_order.c b/src/bind_order.c index 407e29037..dd38f4adb 100644 --- a/src/bind_order.c +++ b/src/bind_order.c @@ -8,6 +8,7 @@ #include /* lua includes */ +#include #include #include diff --git a/src/bind_process.c b/src/bind_process.c index 947458ce5..f9f99284e 100755 --- a/src/bind_process.c +++ b/src/bind_process.c @@ -4,20 +4,22 @@ #include "bind_process.h" +#include "battle.h" +#include "economy.h" +#include "laws.h" +#include "magic.h" +#include "market.h" +#include "move.h" +#include "study.h" + #include #include #include #include #include #include -#include "battle.h" -#include "economy.h" -#include "keyword.h" -#include "laws.h" -#include "magic.h" -#include "market.h" -#include "move.h" -#include "study.h" + +#include "util/keyword.h" #define PROC_LAND_REGION 0x0001 #define PROC_LONG_ORDER 0x0002 @@ -76,10 +78,6 @@ void process_battle(void) { do_battles(); } -void process_siege(void) { - process_cmd(K_BESIEGE, siege_cmd, PROC_LAND_REGION); -} - void process_update_long_order(void) { region * r; for (r = regions; r; r = r->next) { diff --git a/src/bind_region.c b/src/bind_region.c index b49ceb078..4a466b46f 100644 --- a/src/bind_region.c +++ b/src/bind_region.c @@ -8,43 +8,41 @@ #include "bind_building.h" #include "teleport.h" +#include "direction.h" +#include #include -#include #include #include #include #include -#include #include -#include -#include #include #include #include #include -#include + +#include +#include +#include +#include +#include +#include + #include #include -#include -#include -#include -#include -#include -#include - -#include - +#include +#include #include -#include #include +#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); + region *self = (region *)tolua_tousertype(L, 1, NULL); + const char *str = tolua_tostring(L, 2, NULL); int n = 0; if (self->msgs) { mlist * ml = self->msgs->begin; @@ -74,21 +72,21 @@ int tolua_regionlist_next(lua_State * L) static int tolua_region_get_id(lua_State * L) { - region *self = (region *)tolua_tousertype(L, 1, 0); + region *self = (region *)tolua_tousertype(L, 1, NULL); lua_pushinteger(L, self->uid); return 1; } static int tolua_region_get_blocked(lua_State * L) { - region *self = (region *)tolua_tousertype(L, 1, 0); + region *self = (region *)tolua_tousertype(L, 1, NULL); lua_pushboolean(L, (self->flags&RF_BLOCKED) != 0); return 1; } static int tolua_region_set_blocked(lua_State * L) { - region *self = (region *)tolua_tousertype(L, 1, 0); + region *self = (region *)tolua_tousertype(L, 1, NULL); bool flag = !!tolua_toboolean(L, 2, 1); if (flag) self->flags |= RF_BLOCKED; else self->flags &= ~RF_BLOCKED; @@ -97,36 +95,36 @@ static int tolua_region_set_blocked(lua_State * L) static int tolua_region_get_x(lua_State * L) { - region *self = (region *)tolua_tousertype(L, 1, 0); + region *self = (region *)tolua_tousertype(L, 1, NULL); lua_pushinteger(L, self->x); return 1; } static int tolua_region_get_y(lua_State * L) { - region *self = (region *)tolua_tousertype(L, 1, 0); + region *self = (region *)tolua_tousertype(L, 1, NULL); lua_pushinteger(L, self->y); return 1; } static int tolua_region_get_plane(lua_State * L) { - region *r = (region *)tolua_tousertype(L, 1, 0); + region *r = (region *)tolua_tousertype(L, 1, NULL); tolua_pushusertype(L, rplane(r), TOLUA_CAST "plane"); return 1; } static int tolua_region_get_terrain(lua_State * L) { - region *self = (region *)tolua_tousertype(L, 1, 0); + region *self = (region *)tolua_tousertype(L, 1, NULL); tolua_pushstring(L, self->terrain->_name); return 1; } static int tolua_region_set_terrain(lua_State * L) { - region *r = (region *)tolua_tousertype(L, 1, 0); - const char *tname = tolua_tostring(L, 2, 0); + region *r = (region *)tolua_tousertype(L, 1, NULL); + const char *tname = tolua_tostring(L, 2, NULL); if (tname) { const terrain_type *terrain = get_terrain(tname); if (terrain) { @@ -138,7 +136,7 @@ static int tolua_region_set_terrain(lua_State * L) static int tolua_region_get_terrainname(lua_State * L) { - region *self = (region *)tolua_tousertype(L, 1, 0); + region *self = (region *)tolua_tousertype(L, 1, NULL); attrib *a = a_find(self->attribs, &at_racename); if (a) { tolua_pushstring(L, get_racename(a)); @@ -149,8 +147,8 @@ static int tolua_region_get_terrainname(lua_State * L) static int tolua_region_set_owner(lua_State * L) { - region *r = (region *)tolua_tousertype(L, 1, 0); - struct faction *f = (struct faction *)tolua_tousertype(L, 2, 0); + region *r = (region *)tolua_tousertype(L, 1, NULL); + struct faction *f = (struct faction *)tolua_tousertype(L, 2, NULL); if (r) { region_set_owner(r, f, turn); } @@ -159,7 +157,7 @@ static int tolua_region_set_owner(lua_State * L) static int tolua_region_get_owner(lua_State * L) { - region *r = (region *)tolua_tousertype(L, 1, 0); + region *r = (region *)tolua_tousertype(L, 1, NULL); if (r) { struct faction *f = region_get_owner(r); tolua_pushusertype(L, f, TOLUA_CAST "faction"); @@ -170,8 +168,8 @@ static int tolua_region_get_owner(lua_State * L) static int tolua_region_set_terrainname(lua_State * L) { - region *self = (region *)tolua_tousertype(L, 1, 0); - const char *name = tolua_tostring(L, 2, 0); + region *self = (region *)tolua_tousertype(L, 1, NULL); + const char *name = tolua_tostring(L, 2, NULL); if (name == NULL) { a_removeall(&self->attribs, &at_racename); } @@ -183,42 +181,42 @@ static int tolua_region_set_terrainname(lua_State * L) static int tolua_region_get_info(lua_State * L) { - region *self = (region *)tolua_tousertype(L, 1, 0); + region *self = (region *)tolua_tousertype(L, 1, NULL); tolua_pushstring(L, region_getinfo(self)); return 1; } static int tolua_region_set_info(lua_State * L) { - region *self = (region *)tolua_tousertype(L, 1, 0); - region_setinfo(self, tolua_tostring(L, 2, 0)); + region *self = (region *)tolua_tousertype(L, 1, NULL); + region_setinfo(self, tolua_tostring(L, 2, NULL)); return 0; } static int tolua_region_get_name(lua_State * L) { - region *self = (region *)tolua_tousertype(L, 1, 0); + region *self = (region *)tolua_tousertype(L, 1, NULL); tolua_pushstring(L, region_getname(self)); return 1; } static int tolua_region_set_name(lua_State * L) { - region *self = (region *)tolua_tousertype(L, 1, 0); - region_setname(self, tolua_tostring(L, 2, 0)); + region *self = (region *)tolua_tousertype(L, 1, NULL); + region_setname(self, tolua_tostring(L, 2, NULL)); return 0; } static int tolua_region_get_morale(lua_State * L) { - region *r = (region *)tolua_tousertype(L, 1, 0); + region *r = (region *)tolua_tousertype(L, 1, NULL); lua_pushinteger(L, region_get_morale(r)); return 1; } static int tolua_region_set_morale(lua_State * L) { - region *r = (region *)tolua_tousertype(L, 1, 0); + region *r = (region *)tolua_tousertype(L, 1, NULL); region_set_morale(r, (int)tolua_tonumber(L, 2, 0), turn); return 0; } @@ -226,14 +224,14 @@ static int tolua_region_set_morale(lua_State * L) /* region mourning this turn */ static int tolua_region_get_is_mourning(lua_State * L) { - region *r = (region *)tolua_tousertype(L, 1, 0); + region *r = (region *)tolua_tousertype(L, 1, NULL); lua_pushboolean(L, is_mourning(r, turn+1)); return 1; } static int tolua_region_get_adj(lua_State * L) { - region *r = (region *)tolua_tousertype(L, 1, 0); + region *r = (region *)tolua_tousertype(L, 1, NULL); region *rn[MAXDIRECTIONS]; int d, idx; get_neighbours(r, rn); @@ -250,7 +248,7 @@ static int tolua_region_get_adj(lua_State * L) static int tolua_region_get_luxury(lua_State * L) { - region *r = (region *)tolua_tousertype(L, 1, 0); + region *r = (region *)tolua_tousertype(L, 1, NULL); if (r->land) { const item_type *lux = r_luxury(r); if (lux) { @@ -264,8 +262,8 @@ static int tolua_region_get_luxury(lua_State * L) static int tolua_region_set_luxury(lua_State * L) { - region *r = (region *)tolua_tousertype(L, 1, 0); - const char *name = tolua_tostring(L, 2, 0); + region *r = (region *)tolua_tousertype(L, 1, NULL); + const char *name = tolua_tostring(L, 2, NULL); if (r->land && name) { const item_type *lux = r_luxury(r); const item_type *itype = it_find(name); @@ -279,9 +277,9 @@ static int tolua_region_set_luxury(lua_State * L) static int tolua_region_set_herb(lua_State * L) { - region *r = (region *)tolua_tousertype(L, 1, 0); + region *r = (region *)tolua_tousertype(L, 1, NULL); if (r->land) { - const char *name = tolua_tostring(L, 2, 0); + const char *name = tolua_tostring(L, 2, NULL); const item_type *itype = it_find(name); if (itype && (itype->flags & ITF_HERB)) { r->land->herbtype = itype; @@ -292,7 +290,7 @@ static int tolua_region_set_herb(lua_State * L) static int tolua_region_get_herb(lua_State * L) { - region *r = (region *)tolua_tousertype(L, 1, 0); + region *r = (region *)tolua_tousertype(L, 1, NULL); if (r->land && r->land->herbtype) { const char *name = r->land->herbtype->rtype->_name; tolua_pushstring(L, name); @@ -303,7 +301,7 @@ static int tolua_region_get_herb(lua_State * L) static int tolua_region_get_next(lua_State * L) { - region *self = (region *)tolua_tousertype(L, 1, 0); + region *self = (region *)tolua_tousertype(L, 1, NULL); direction_t dir = (direction_t)tolua_tonumber(L, 2, 0); if (dir >= 0 && dir < MAXDIRECTIONS) { @@ -315,7 +313,7 @@ static int tolua_region_get_next(lua_State * L) static int tolua_region_get_flag(lua_State * L) { - region *self = (region *)tolua_tousertype(L, 1, 0); + region *self = (region *)tolua_tousertype(L, 1, NULL); int bit = (int)tolua_tonumber(L, 2, 0); lua_pushboolean(L, (self->flags & (1 << bit))); @@ -324,7 +322,7 @@ static int tolua_region_get_flag(lua_State * L) static int tolua_region_set_flag(lua_State * L) { - region *self = (region *)tolua_tousertype(L, 1, 0); + region *self = (region *)tolua_tousertype(L, 1, NULL); int bit = (int)tolua_tonumber(L, 2, 0); int set = tolua_toboolean(L, 3, 1); @@ -337,8 +335,8 @@ static int tolua_region_set_flag(lua_State * L) static int tolua_region_get_resourcelevel(lua_State * L) { - region *r = (region *)tolua_tousertype(L, 1, 0); - const char *type = tolua_tostring(L, 2, 0); + region *r = (region *)tolua_tousertype(L, 1, NULL); + const char *type = tolua_tostring(L, 2, NULL); const resource_type *rtype = rt_find(type); if (rtype != NULL) { const rawmaterial *rm; @@ -373,9 +371,9 @@ static int tolua_region_get_resource(lua_State * L) const resource_type *rtype; int result; - r = (region *)tolua_tousertype(L, 1, 0); + r = (region *)tolua_tousertype(L, 1, NULL); LUA_ASSERT(r != NULL, "invalid parameter"); - type = tolua_tostring(L, 2, 0); + type = tolua_tostring(L, 2, NULL); LUA_ASSERT(type != NULL, "invalid parameter"); result = special_resource(type); @@ -404,8 +402,8 @@ static int tolua_region_get_resource(lua_State * L) 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); + region *r = (region *)tolua_tousertype(L, 1, NULL); + const char *type = tolua_tostring(L, 2, NULL); int result, value = (int)tolua_tonumber(L, 3, 0); const resource_type *rtype; @@ -430,7 +428,7 @@ static int tolua_region_set_resource(lua_State * L) static int tolua_region_destroy(lua_State * L) { - region *self = (region *)tolua_tousertype(L, 1, 0); + region *self = (region *)tolua_tousertype(L, 1, NULL); remove_region(®ions, self); return 0; } @@ -439,7 +437,7 @@ static int tolua_region_create(lua_State * L) { int x = (int)tolua_tonumber(L, 1, 0); int y = (int)tolua_tonumber(L, 2, 0); - const char *tname = tolua_tostring(L, 3, 0); + const char *tname = tolua_tostring(L, 3, NULL); if (tname) { plane *pl = findplane(x, y); const terrain_type *terrain = get_terrain(tname); @@ -449,7 +447,7 @@ static int tolua_region_create(lua_State * L) return 0; } - assert(!pnormalize(&x, &y, pl)); + pnormalize(&x, &y, pl); r = result = findregion(x, y); if (r != NULL && r->units != NULL) { @@ -472,7 +470,7 @@ static int tolua_region_create(lua_State * L) static int tolua_region_get_units(lua_State * L) { - region *self = (region *)tolua_tousertype(L, 1, 0); + region *self = (region *)tolua_tousertype(L, 1, NULL); unit **unit_ptr = (unit **)lua_newuserdata(L, sizeof(unit *)); luaL_getmetatable(L, "unit"); @@ -486,7 +484,7 @@ static int tolua_region_get_units(lua_State * L) static int tolua_region_get_buildings(lua_State * L) { - region *self = (region *)tolua_tousertype(L, 1, 0); + region *self = (region *)tolua_tousertype(L, 1, NULL); building **building_ptr = (building **)lua_newuserdata(L, sizeof(building *)); @@ -501,7 +499,7 @@ static int tolua_region_get_buildings(lua_State * L) static int tolua_region_get_ships(lua_State * L) { - region *self = (region *)tolua_tousertype(L, 1, 0); + region *self = (region *)tolua_tousertype(L, 1, NULL); ship **ship_ptr = (ship **)lua_newuserdata(L, sizeof(ship *)); luaL_getmetatable(L, "ship"); @@ -515,7 +513,7 @@ static int tolua_region_get_ships(lua_State * L) static int tolua_region_get_age(lua_State * L) { - region *self = (region *)tolua_tousertype(L, 1, 0); + region *self = (region *)tolua_tousertype(L, 1, NULL); if (self) { lua_pushinteger(L, self->age); @@ -526,7 +524,7 @@ static int tolua_region_get_age(lua_State * L) static int tolua_region_get_peasants(lua_State * L) { - region *self = (region *)tolua_tousertype(L, 1, 0); + region *self = (region *)tolua_tousertype(L, 1, NULL); if (self) { lua_pushinteger(L, self->land ? self->land->peasants : 0); @@ -537,7 +535,7 @@ static int tolua_region_get_peasants(lua_State * L) static int tolua_region_set_peasants(lua_State * L) { - region *self = (region *)tolua_tousertype(L, 1, 0); + region *self = (region *)tolua_tousertype(L, 1, NULL); if (self && self->land) { self->land->peasants = lua_tointeger(L, 2); @@ -547,37 +545,22 @@ static int tolua_region_set_peasants(lua_State * L) static int tolua_region_getkey(lua_State * L) { - region *self = (region *)tolua_tousertype(L, 1, 0); - const char *name = tolua_tostring(L, 2, 0); + region *self = (region *)tolua_tousertype(L, 1, NULL); + const char *name = tolua_tostring(L, 2, NULL); int flag = atoi36(name); - - lua_pushboolean(L, key_get(self->attribs, flag)); - return 1; -} - -static int tolua_region_getastral(lua_State * L) -{ - region *r = (region *)tolua_tousertype(L, 1, 0); - region *rt = r_standard_to_astral(r); - - if (!rt) { - const char *tname = tolua_tostring(L, 2, 0); - plane *pl = get_astralplane(); - rt = new_region(real2tp(r->x), real2tp(r->y), pl, 0); - if (tname) { - const terrain_type *terrain = get_terrain(tname); - terraform_region(rt, terrain); - } + int value = key_get(self->attribs, flag); + if (value != 0) { + lua_pushinteger(L, value); + return 1; } - tolua_pushusertype(L, rt, TOLUA_CAST "region"); - return 1; + return 0; } static int tolua_region_setkey(lua_State * L) { - region *self = (region *)tolua_tousertype(L, 1, 0); - const char *name = tolua_tostring(L, 2, 0); - int value = (int)tolua_tonumber(L, 3, 0); + region *self = (region *)tolua_tousertype(L, 1, NULL); + const char *name = tolua_tostring(L, 2, NULL); + int value = (int)tolua_tonumber(L, 3, 1); int flag = atoi36(name); if (value) { @@ -589,9 +572,27 @@ static int tolua_region_setkey(lua_State * L) return 0; } +static int tolua_region_getastral(lua_State * L) +{ + region *r = (region *)tolua_tousertype(L, 1, NULL); + region *rt = r_standard_to_astral(r); + + if (!rt) { + const char *tname = tolua_tostring(L, 2, NULL); + plane *pl = get_astralplane(); + rt = new_region(real2tp(r->x), real2tp(r->y), pl, 0); + if (tname) { + const terrain_type *terrain = get_terrain(tname); + terraform_region(rt, terrain); + } + } + tolua_pushusertype(L, rt, TOLUA_CAST "region"); + return 1; +} + static int tolua_region_tostring(lua_State * L) { - region *self = (region *)tolua_tousertype(L, 1, 0); + region *self = (region *)tolua_tousertype(L, 1, NULL); lua_pushstring(L, regionname(self, NULL)); return 1; } @@ -607,7 +608,7 @@ static int tolua_plane_get(lua_State * L) static int tolua_plane_erase(lua_State *L) { - plane *self = (plane *)tolua_tousertype(L, 1, 0); + plane *self = (plane *)tolua_tousertype(L, 1, NULL); remove_plane(self); return 0; } @@ -619,7 +620,7 @@ static int tolua_plane_create(lua_State * L) int y = (int)tolua_tonumber(L, 3, 0); int width = (int)tolua_tonumber(L, 4, 0); int height = (int)tolua_tonumber(L, 5, 0); - const char *name = tolua_tostring(L, 6, 0); + const char *name = tolua_tostring(L, 6, NULL); plane *pl; pl = create_new_plane(id, name, x, x + width - 1, y, y + height - 1, 0); @@ -630,15 +631,15 @@ static int tolua_plane_create(lua_State * L) static int tolua_plane_get_name(lua_State * L) { - plane *self = (plane *)tolua_tousertype(L, 1, 0); + plane *self = (plane *)tolua_tousertype(L, 1, NULL); tolua_pushstring(L, self->name); return 1; } static int tolua_plane_set_name(lua_State * L) { - plane *self = (plane *)tolua_tousertype(L, 1, 0); - const char *str = tolua_tostring(L, 2, 0); + plane *self = (plane *)tolua_tousertype(L, 1, NULL); + const char *str = tolua_tostring(L, 2, NULL); free(self->name); if (str) self->name = str_strdup(str); @@ -649,14 +650,14 @@ static int tolua_plane_set_name(lua_State * L) static int tolua_plane_get_id(lua_State * L) { - plane *self = (plane *)tolua_tousertype(L, 1, 0); + plane *self = (plane *)tolua_tousertype(L, 1, NULL); lua_pushinteger(L, self->id); return 1; } static int tolua_plane_normalize(lua_State * L) { - plane *self = (plane *)tolua_tousertype(L, 1, 0); + plane *self = (plane *)tolua_tousertype(L, 1, NULL); int x = (int)tolua_tonumber(L, 2, 0); int y = (int)tolua_tonumber(L, 3, 0); pnormalize(&x, &y, self); @@ -667,14 +668,14 @@ static int tolua_plane_normalize(lua_State * L) static int tolua_plane_tostring(lua_State * L) { - plane *self = (plane *)tolua_tousertype(L, 1, 0); + plane *self = (plane *)tolua_tousertype(L, 1, NULL); lua_pushstring(L, self->name); return 1; } static int tolua_plane_get_size(lua_State * L) { - plane *pl = (plane *)tolua_tousertype(L, 1, 0); + plane *pl = (plane *)tolua_tousertype(L, 1, NULL); lua_pushinteger(L, plane_width(pl)); lua_pushinteger(L, plane_height(pl)); return 2; @@ -699,8 +700,8 @@ static int tolua_distance(lua_State * L) } 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); + region *self = (region *)tolua_tousertype(L, 1, NULL); + const char *name = tolua_tostring(L, 2, NULL); if (self->attribs) { curse * c = get_curse(self->attribs, ct_find(name)); if (c) { @@ -712,8 +713,8 @@ static int tolua_region_get_curse(lua_State *L) { } 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); + region *self = (region *)tolua_tousertype(L, 1, NULL); + const char *name = tolua_tostring(L, 2, NULL); attrib * a = a_find(self->attribs, at_find(name)); lua_pushboolean(L, a != NULL); return 1; diff --git a/src/bind_ship.c b/src/bind_ship.c index 2a1d75271..d335d996d 100644 --- a/src/bind_ship.c +++ b/src/bind_ship.c @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/bind_storage.c b/src/bind_storage.c index e1339312c..5df148bb4 100644 --- a/src/bind_storage.c +++ b/src/bind_storage.c @@ -6,21 +6,18 @@ #include -#include +#include #include #include #include -#include -#include -#include #include #include #include -#include #include +#include #include static int tolua_storage_create(lua_State * L) diff --git a/src/bind_tolua.c b/src/bind_tolua.c index 669d5848b..d681b9088 100644 --- a/src/bind_tolua.c +++ b/src/bind_tolua.c @@ -12,6 +12,8 @@ #include "settings.pkg.c" #pragma warning(pop) +#include + void tolua_bind_open(lua_State * L) { tolua_eressea_open(L); tolua_process_open(L); diff --git a/src/bind_unit.c b/src/bind_unit.c index fddcd5608..4e3047367 100644 --- a/src/bind_unit.c +++ b/src/bind_unit.c @@ -5,15 +5,22 @@ #include "bind_unit.h" #include "alchemy.h" #include "bindings.h" -#include "move.h" #include "reports.h" #include "guard.h" +#include "magic.h" +#include "skill.h" -/* attributes includes */ -#include -#include +/* util includes */ +#include +#include +#include +#include +#include +#include "util/variant.h" /* kernel includes */ +#include "kernel/skills.h" +#include "kernel/types.h" #include #include #include @@ -31,21 +38,20 @@ #include #include -/* util includes */ -#include -#include -#include -#include -#include -#include +/* attributes includes */ +#include +#include #include +#include +#include #include #include #include #include +#include #include #include @@ -56,7 +62,7 @@ static int tolua_bufunit(lua_State * L) { if (f) { char buf[8192]; int mode = (int)tolua_tonumber(L, 3, (int)seen_unit); - bufunit(f, u, mode, buf, sizeof(buf)); + bufunit_depr(f, u, mode, buf, sizeof(buf)); tolua_pushstring(L, buf); return 1; } @@ -193,7 +199,7 @@ static int tolua_unit_set_id(lua_State * L) 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)); + lua_pushinteger(L, max_spellpoints_depr(self->region, self)); return 1; } @@ -270,8 +276,12 @@ static int tolua_unit_set_guard(lua_State * L) static const char *unit_getmagic(const unit * u) { - sc_mage *mage = get_mage_depr(u); - return mage ? magic_school[mage->magietyp] : NULL; + struct sc_mage *mage = get_mage(u); + if (mage) { + magic_t mtype = mage_get_type(mage); + return magic_school[mtype]; + } + return NULL; } static int tolua_unit_get_magic(lua_State * L) @@ -283,16 +293,15 @@ static int tolua_unit_get_magic(lua_State * L) static void unit_setmagic(unit * u, const char *type) { - sc_mage *mage = get_mage(u); - int mtype; - for (mtype = 0; mtype != MAXMAGIETYP; ++mtype) { - if (strcmp(magic_school[mtype], type) == 0) - break; - } - if (mtype == MAXMAGIETYP) - return; + struct sc_mage *mage = get_mage(u); if (mage == NULL) { - mage = create_mage(u, (magic_t)mtype); + int mtype; + for (mtype = 0; mtype != MAXMAGIETYP; ++mtype) { + if (strcmp(magic_school[mtype], type) == 0) { + create_mage(u, (magic_t)mtype); + return; + } + } } } @@ -515,7 +524,7 @@ static int tolua_unit_addspell(lua_State * L) return EINVAL; } else { - unit_add_spell(u, 0, sp, level); + unit_add_spell(u, sp, level); } lua_pushinteger(L, err); @@ -742,8 +751,8 @@ static int tolua_unit_get_items(lua_State * L) static int tolua_unit_get_spells(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - sc_mage *mage = self ? get_mage_depr(self) : 0; - spellbook *sb = mage ? mage->spellbook : 0; + struct sc_mage *mage = self ? get_mage(self) : NULL; + spellbook *sb = mage_get_spellbook(mage); selist *slist = 0; if (sb) { selist **slist_ptr = &sb->spells; diff --git a/src/bindings.c b/src/bindings.c index d72bddac2..c46c0e80e 100755 --- a/src/bindings.c +++ b/src/bindings.c @@ -4,30 +4,39 @@ #include "bindings.h" +#include "console.h" +#include "gamedb.h" +#include "helpers.h" +#include "laws.h" +#include "magic.h" +#include "reports.h" +#include "skill.h" +#include "study.h" +#include "summary.h" +#include "teleport.h" + #include "kernel/calendar.h" #include "kernel/config.h" #include "kernel/alliance.h" #include "kernel/building.h" +#include "kernel/build.h" #include "kernel/curse.h" #include "kernel/unit.h" #include "kernel/terrain.h" #include "kernel/messages.h" -#include "kernel/region.h" -#include "kernel/building.h" #include "kernel/plane.h" -#include "kernel/race.h" -#include "kernel/item.h" -#include "kernel/order.h" -#include "kernel/ship.h" -#include "kernel/faction.h" +#include "kernel/region.h" #include "kernel/save.h" +#include "kernel/ship.h" #include "kernel/spell.h" +#include "kernel/types.h" +#include "kernel/item.h" +#include "kernel/faction.h" #include "kernel/spellbook.h" #include "races/races.h" #include "bind_unit.h" #include "bind_storage.h" -#include "bind_building.h" #include "bind_message.h" #include "bind_building.h" #include "bind_faction.h" @@ -36,42 +45,30 @@ #include "bind_gmtool.h" #include "bind_region.h" -#include "helpers.h" -#include "console.h" -#include "reports.h" -#include "study.h" -#include "economy.h" -#include "summary.h" -#include "teleport.h" -#include "laws.h" -#include "monsters.h" -#include "market.h" - #include -#include -#include +#include #include #include -#include #include #include -#include #include #include #include -#include -#include +#include #include #include #include #include -#include -#include #include +#include +#include +#include +#include +#include #define TOLUA_PKG(NAME) void tolua_##NAME##_open(lua_State * L) @@ -153,15 +150,6 @@ int tolua_itemlist_next(lua_State * L) return 0; } -static int tolua_getkey(lua_State * L) -{ - const char *name = tolua_tostring(L, 1, 0); - int flag = atoi36(name); - - lua_pushboolean(L, key_get(global.attribs, flag)); - return 1; -} - static int tolua_translate(lua_State * L) { const char *str = tolua_tostring(L, 1, 0); @@ -175,20 +163,6 @@ static int tolua_translate(lua_State * L) return 0; } -static int tolua_setkey(lua_State * L) -{ - const char *name = tolua_tostring(L, 1, 0); - int value = (int)tolua_tonumber(L, 3, 0); - int flag = atoi36(name); - if (value) { - key_set(&global.attribs, flag, value); - } - else { - key_unset(&global.attribs, flag); - } - return 0; -} - static int tolua_random(lua_State * L) { lua_pushinteger(L, rng_int()); @@ -365,13 +339,6 @@ static int tolua_update_owners(lua_State * L) return 0; } -static int tolua_update_subscriptions(lua_State * L) -{ - UNUSED_ARG(L); - update_subscriptions(); - return 0; -} - static int tolua_remove_empty_units(lua_State * L) { UNUSED_ARG(L); @@ -470,7 +437,14 @@ static int tolua_write_passwords(lua_State * L) { int result = writepasswd(); lua_pushinteger(L, result); - return 0; + return 1; +} + +static int tolua_write_database(lua_State * L) +{ + int result = gamedb_update(); + lua_pushinteger(L, result); + return 1; } static int tolua_write_summary(lua_State * L) @@ -506,7 +480,7 @@ static int tolua_get_region(lua_State * L) int x = (int)tolua_tonumber(L, 1, 0); int y = (int)tolua_tonumber(L, 2, 0); region *r; - assert(!pnormalize(&x, &y, findplane(x, y))); + pnormalize(&x, &y, findplane(x, y)); r = findregion(x, y); tolua_pushusertype(L, r, TOLUA_CAST "region"); return 1; @@ -843,7 +817,7 @@ static int tolua_report_unit(lua_State * L) char buffer[512]; unit *u = (unit *)tolua_tousertype(L, 1, 0); faction *f = (faction *)tolua_tousertype(L, 2, 0); - bufunit(f, u, seen_unit, buffer, sizeof(buffer)); + bufunit_depr(f, u, seen_unit, buffer, sizeof(buffer)); tolua_pushstring(L, buffer); return 1; } @@ -982,6 +956,7 @@ int tolua_bindings_open(lua_State * L, const dictionary *inifile) tolua_function(L, TOLUA_CAST "write_report", tolua_write_report); tolua_function(L, TOLUA_CAST "write_summary", tolua_write_summary); tolua_function(L, TOLUA_CAST "write_passwords", tolua_write_passwords); + tolua_function(L, TOLUA_CAST "write_database", tolua_write_database); tolua_function(L, TOLUA_CAST "message_unit", tolua_message_unit); tolua_function(L, TOLUA_CAST "message_faction", tolua_message_faction); tolua_function(L, TOLUA_CAST "message_region", tolua_message_region); @@ -998,13 +973,10 @@ int tolua_bindings_open(lua_State * L, const dictionary *inifile) tolua_function(L, TOLUA_CAST "dice_roll", tolua_dice_rand); tolua_function(L, TOLUA_CAST "get_nmrs", tolua_get_nmrs); tolua_function(L, TOLUA_CAST "remove_empty_units", tolua_remove_empty_units); - tolua_function(L, TOLUA_CAST "update_subscriptions", tolua_update_subscriptions); tolua_function(L, TOLUA_CAST "update_scores", tolua_update_scores); tolua_function(L, TOLUA_CAST "update_owners", tolua_update_owners); tolua_function(L, TOLUA_CAST "learn_skill", tolua_learn_skill); tolua_function(L, TOLUA_CAST "create_curse", tolua_create_curse); - 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 "spells", tolua_get_spells); tolua_function(L, TOLUA_CAST "equip_newunits", tolua_equip_newunits); diff --git a/src/chaos.c b/src/chaos.c index 1ec431b7e..615113656 100644 --- a/src/chaos.c +++ b/src/chaos.c @@ -34,7 +34,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include -#include +#include #include #include diff --git a/src/checker.c b/src/checker.c new file mode 100644 index 000000000..27648e7af --- /dev/null +++ b/src/checker.c @@ -0,0 +1,92 @@ +#ifdef _MSV_VER +#include +#endif + +#include "util/order_parser.h" +#include "util/keyword.h" +#include "util/language.h" +#include "util/path.h" +#include "util/pofile.h" + +#include +#include +#include +#include + +typedef struct parser_state { + FILE * F; +} parser_state; + +static void handle_order(void *userData, const char *str) { + parser_state * state = (parser_state*)userData; + fputs(str, state->F); + fputc('\n', state->F); +} + +int parsefile(FILE *F) { + OP_Parser parser; + char buf[1024]; + int done = 0, err = 0; + parser_state state = { NULL }; + + state.F = stdout; + + parser = OP_ParserCreate(); + OP_SetOrderHandler(parser, handle_order); + OP_SetUserData(parser, &state); + + while (!done) { + size_t len = (int)fread(buf, 1, sizeof(buf), F); + if (ferror(F)) { + /* TODO: error message */ + err = errno; + break; + } + done = feof(F); + if (OP_Parse(parser, buf, len, done) == OP_STATUS_ERROR) { + /* TODO: error message */ + err = (int)OP_GetErrorCode(parser); + break; + } + } + OP_ParserFree(parser); + return err; +} + +static int handle_po(const char *msgid, const char *msgstr, const char *msgctxt, void *data) { + struct locale *lang = (struct locale *)data; + if (msgctxt) { + if (strcmp(msgctxt, "keyword") == 0) { + keyword_t kwd = findkeyword(msgid); + init_keyword(lang, kwd, msgstr); + locale_setstring(lang, mkname("keyword", keywords[kwd]), msgstr); + } + } + return 0; +} + +static void read_config(const char *respath) { + char path[PATH_MAX]; + struct locale *lang; + lang = get_or_create_locale("de"); + path_join(respath, "translations/strings.de.po", path, sizeof(path)); + pofile_read(path, handle_po, lang); +} + +int main(int argc, char **argv) { + FILE * F = stdin; + if (argc > 1) { + const char *filename = argv[1]; + F = fopen(filename, "r"); + if (!F) { + perror(filename); + return -1; + } + } + read_config("../git"); + parsefile(F); + if (F != stdin) { + fclose(F); + } + return 0; +} diff --git a/src/console.c b/src/console.c index 7a32b83f0..f134b2164 100644 --- a/src/console.c +++ b/src/console.c @@ -5,13 +5,12 @@ /* lua includes */ #include +#include #include -#include /* libc includes */ #include #include -#include #include #include diff --git a/src/contact.c b/src/contact.c new file mode 100644 index 000000000..635bdbd3d --- /dev/null +++ b/src/contact.c @@ -0,0 +1,136 @@ +#ifdef _MSC_VER +#include +#endif + +#include "contact.h" + +#include "kernel/attrib.h" +#include "kernel/faction.h" +#include "kernel/messages.h" +#include "kernel/order.h" +#include "kernel/unit.h" + +#include "util/base36.h" +#include "util/param.h" +#include "util/parser.h" + +#include + +static attrib_type at_contact_unit = { + "contact_unit", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + NO_WRITE, + NO_READ +}; + +void contact_unit(unit * u, const unit * u2) +{ + attrib *a = a_find(u->attribs, &at_contact_unit); + while (a && a->type == &at_contact_unit) { + if (a->data.v == u2) { + return; + } + a = a->next; + } + a_add(&u->attribs, a_new(&at_contact_unit))->data.v = (void *)u2; +} + +static attrib_type at_contact_faction = { + "contact_faction", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + NO_WRITE, + NO_READ +}; + +void contact_faction(unit * u, const faction * f) +{ + attrib *a = a_find(u->attribs, &at_contact_faction); + while (a && a->type == &at_contact_faction) { + if (a->data.v == f) { + return; + } + a = a->next; + } + a_add(&u->attribs, a_new(&at_contact_faction))->data.v = (void *)f; +} + +bool ucontact(const unit * u, const unit * u2) +/* Prueft, ob u den Kontaktiere-Befehl zu u2 gesetzt hat. */ +{ + attrib *a; + + if (u->faction == u2->faction) { + return true; + } + /* Explizites KONTAKTIERE */ + for (a = u->attribs; a; a = a->next) { + if (a->type == &at_contact_unit) { + if (u2 == a->data.v) { + return true; + } + } + else if (a->type == &at_contact_faction) { + if (u2->faction == a->data.v) { + return true; + } + } + } + return false; +} + +int contact_cmd(unit * u, order * ord) +{ + char token[16]; + const char *str; + param_t p; + + init_order(ord, u->faction->locale); + str = gettoken(token, sizeof(token)); + p = findparam(str, u->faction->locale); + if (p == P_FACTION) { + /* new-style syntax, KONTAKTIERE PARTEI foo */ + faction * f = getfaction(); + if (!f) { + cmistake(u, ord, 66, MSG_EVENT); + } + else { + contact_faction(u, f); + return 0; + } + } + else if (p == P_UNIT) { + /* new-style syntax, KONTAKTIERE EINHEIT [TEMP] foo */ + unit *u2 = NULL; + if (GET_UNIT == getunit(u->region, u->faction, &u2)) { + assert(u2); + contact_unit(u, u2); + return 0; + } + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, + "feedback_unit_not_found", NULL)); + } + else { + /* old-style syntax, KONTAKTIERE foo */ + unit *u2; + int n = 0; + if (p == P_TEMP) { + n = getid(); + u2 = findnewunit(u->region, u->faction, n); + } + else { + n = atoi36((const char *)str); + u2 = findunit(n); + } + if (u2 != NULL) { + contact_unit(u, u2); + return 0; + } + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, + "feedback_unit_not_found", NULL)); + } + return -1; +} diff --git a/src/contact.h b/src/contact.h new file mode 100644 index 000000000..0ab3d1e50 --- /dev/null +++ b/src/contact.h @@ -0,0 +1,12 @@ +#pragma once + +#include + +struct faction; +struct order; +struct unit; + +bool ucontact(const struct unit *u, const struct unit *u2); +void contact_unit(struct unit *u, const struct unit *c); +void contact_faction(struct unit * u, const struct faction * f); +int contact_cmd(struct unit * u, struct order * ord); diff --git a/src/contact.test.c b/src/contact.test.c new file mode 100644 index 000000000..3a9cc355e --- /dev/null +++ b/src/contact.test.c @@ -0,0 +1,84 @@ +#include "contact.h" + +#include "kernel/faction.h" +#include "kernel/order.h" +#include "kernel/unit.h" + +#include "util/language.h" +#include "util/param.h" + +#include "tests.h" +#include + +struct region; + +static void test_contact(CuTest *tc) { + struct unit *u1, *u2, *u3; + struct region *r; + struct faction *f; + + test_setup(); + r = test_create_plain(0, 0); + f = test_create_faction(NULL); + u1 = test_create_unit(f, r); + u2 = test_create_unit(f, r); + u3 = test_create_unit(test_create_faction(NULL), r); + CuAssertTrue(tc, ucontact(u1, u1)); + CuAssertTrue(tc, ucontact(u1, u2)); + CuAssertTrue(tc, !ucontact(u1, u3)); + contact_unit(u1, u3); + CuAssertTrue(tc, ucontact(u1, u3)); + CuAssertTrue(tc, !ucontact(u2, u3)); + test_teardown(); +} + +static void test_contact_cmd(CuTest *tc) { + struct unit *u, *u2; + struct region *r; + const struct locale *lang; + struct order *ord; + + test_setup(); + r = test_create_plain(0, 0); + u = test_create_unit(test_create_faction(NULL), r); + lang = u->faction->locale; + + u2 = test_create_unit(test_create_faction(NULL), r); + ord = create_order(K_CONTACT, u->faction->locale, "%s %i", + LOC(lang, parameters[P_UNIT]), u2->no); + contact_cmd(u, ord); + CuAssertTrue(tc, ucontact(u, u2)); + free_order(ord); + + u2 = test_create_unit(test_create_faction(NULL), r); + ord = create_order(K_CONTACT, u->faction->locale, "%s %i", + LOC(lang, parameters[P_FACTION]), u2->faction->no); + contact_cmd(u, ord); + CuAssertTrue(tc, ucontact(u, u2)); + free_order(ord); + + u2 = test_create_unit(test_create_faction(NULL), r); + ord = create_order(K_CONTACT, u->faction->locale, "%i", u2->no); + contact_cmd(u, ord); + CuAssertTrue(tc, ucontact(u, u2)); + free_order(ord); + + u2 = test_create_unit(test_create_faction(NULL), r); + usetalias(u2, 42); + ord = create_order(K_CONTACT, u->faction->locale, "%s %i", + LOC(lang, parameters[P_TEMP]), ualias(u2)); + contact_cmd(u, ord); + CuAssertTrue(tc, ucontact(u, u2)); + free_order(ord); + + test_teardown(); +} + +CuSuite *get_contact_suite(void) +{ + CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_contact); + SUITE_ADD_TEST(suite, test_contact_cmd); + + return suite; +} diff --git a/src/creport.c b/src/creport.c index 91d56ca3b..3ac9dffe9 100644 --- a/src/creport.c +++ b/src/creport.c @@ -64,7 +64,7 @@ without prior permission by the authors of Eressea. #include "kernel/unit.h" /* util includes */ -#include +#include #include #include #include @@ -673,9 +673,7 @@ static void cr_output_building(struct stream *out, building *b, if (fno >= 0) { stream_printf(out, "%d;Partei\n", fno); } - if (b->besieged) { - stream_printf(out, "%d;Belagerer\n", b->besieged); - } + cr_output_curses(out, f, b, TYP_BUILDING); } @@ -780,7 +778,6 @@ void cr_output_unit(stream *out, const faction * f, const item_type *lasttype; int pr; item *itm, *show = NULL; - building *b; const char *pzTmp; skill *sv; item result[MAX_INVENTORY]; @@ -802,13 +799,11 @@ void cr_output_unit(stream *out, const faction * f, } if (u->faction == f) { - const attrib *a = NULL; unit *mage; + group * g; - if (fval(u, UFL_GROUP)) - a = a_find(u->attribs, &at_group); - if (a != NULL) { - const group *g = (const group *)a->data.v; + g = get_group(u); + if (g) { stream_printf(out, "%d;gruppe\n", g->gid); } mage = get_familiar_mage(u); @@ -879,16 +874,13 @@ void cr_output_unit(stream *out, const faction * f, if (is_guard(u)) { stream_printf(out, "%d;bewacht\n", 1); } - if ((b = usiege(u)) != NULL) { - stream_printf(out, "%d;belagert\n", b->no); - } /* additional information for own units */ if (u->faction == f || omniscient(f)) { order *ord; const char *xc; const char *c; int i; - sc_mage *mage; + struct sc_mage *mage; i = ualias(u); if (i > 0) @@ -925,7 +917,7 @@ void cr_output_unit(stream *out, const faction * f, } if (is_mage(u)) { stream_printf(out, "%d;Aura\n", get_spellpoints(u)); - stream_printf(out, "%d;Auramax\n", max_spellpoints(u->region, u)); + stream_printf(out, "%d;Auramax\n", max_spellpoints_depr(u->region, u)); } /* default commands */ stream_printf(out, "COMMANDS\n"); @@ -965,19 +957,23 @@ void cr_output_unit(stream *out, const faction * f, } /* spells that this unit can cast */ - mage = get_mage_depr(u); + mage = get_mage(u); if (mage) { int maxlevel = effskill(u, SK_MAGIC, 0); cr_output_spells(out, u, maxlevel); for (i = 0; i != MAXCOMBATSPELLS; ++i) { - const spell *sp = mage->combatspells[i].sp; + int level; + const spell *sp = mage_get_combatspell(mage, i, &level); if (sp) { - const char *name = - translate(mkname("spell", sp->sname), spell_name(sp, lang)); + const char *name; + if (level > maxlevel) { + level = maxlevel; + } stream_printf(out, "KAMPFZAUBER %d\n", i); + name = translate(mkname("spell", sp->sname), spell_name(sp, lang)); stream_printf(out, "\"%s\";name\n", name); - stream_printf(out, "%d;level\n", mage->combatspells[i].level); + stream_printf(out, "%d;level\n", level); } } } @@ -1024,20 +1020,38 @@ static void cr_output_unit_compat(FILE * F, const faction * f, cr_output_unit(&strm, f, u, mode); } -/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ +static void print_ally(const faction *f, faction *af, int status, FILE *F) { + if (af && status > 0) { + fprintf(F, "ALLIANZ %d\n", af->no); + fprintf(F, "\"%s\";Parteiname\n", af->name); + fprintf(F, "%d;Status\n", status & HELP_ALL); + } +} + +struct print_ally_s { + const faction *f; + FILE *F; +}; + +static int print_ally_cb(struct allies *al, faction *af, int status, void *udata) { + struct print_ally_s *data = (struct print_ally_s *)udata; + + UNUSED_ARG(al); + if (af && faction_alive(af)) { + int mode = alliance_status(data->f, af, status); + print_ally(data->f, af, mode, data->F); + } + return 0; +} /* prints allies */ -static void show_allies_cr(FILE * F, const faction * f, const ally * sf) +static void show_allies_cr(FILE * F, const faction * f, const group *g) { - for (; sf; sf = sf->next) - if (sf->faction) { - int mode = alliedgroup(NULL, f, sf->faction, sf, HELP_ALL); - if (mode != 0 && sf->status > 0) { - fprintf(F, "ALLIANZ %d\n", sf->faction->no); - fprintf(F, "\"%s\";Parteiname\n", sf->faction->name); - fprintf(F, "%d;Status\n", sf->status & HELP_ALL); - } - } + struct print_ally_s data; + data.F = F; + data.f = f; + struct allies *sf = g ? g->allies : f->allies; + allies_walk(sf, print_ally_cb, &data); } /* prints allies */ @@ -1063,12 +1077,15 @@ static void cr_find_address(FILE * F, const faction * uf, selist * addresses) while (flist) { const faction *f = (const faction *)selist_get(flist, i); if (uf != f) { + const char *str; fprintf(F, "PARTEI %d\n", f->no); fprintf(F, "\"%s\";Parteiname\n", f->name); if (strcmp(faction_getemail(f), "") != 0) fprintf(F, "\"%s\";email\n", faction_getemail(f)); - if (f->banner) - fprintf(F, "\"%s\";banner\n", f->banner); + str = faction_getbanner(f); + if (str) { + fprintf(F, "\"%s\";banner\n", str); + } fprintf(F, "\"%s\";locale\n", locale_name(f->locale)); if (f->alliance && f->alliance == uf->alliance) { fprintf(F, "%d;alliance\n", f->alliance->id); @@ -1540,7 +1557,7 @@ report_computer(const char *filename, report_context * ctx, const char *bom) static int era = -1; int i; faction *f = ctx->f; - const char *prefix; + const char *prefix, *str; region *r; const char *mailto = config_get("game.email"); const attrib *a; @@ -1634,8 +1651,10 @@ report_computer(const char *filename, report_context * ctx, const char *bom) fprintf(F, "\"%s\";Parteiname\n", f->name); fprintf(F, "\"%s\";email\n", faction_getemail(f)); - if (f->banner) - fprintf(F, "\"%s\";banner\n", f->banner); + str = faction_getbanner(f); + if (str) { + fprintf(F, "\"%s\";banner\n", str); + } print_items(F, f->items, f->locale); fputs("OPTIONEN\n", F); for (i = 0; i != MAXOPTIONS; ++i) { @@ -1647,7 +1666,7 @@ report_computer(const char *filename, report_context * ctx, const char *bom) f->options &= (~flag); } } - show_allies_cr(F, f, f->allies); + show_allies_cr(F, f, NULL); { group *g; for (g = f->groups; g; g = g->next) { @@ -1660,7 +1679,7 @@ report_computer(const char *filename, report_context * ctx, const char *bom) fprintf(F, "\"%s\";typprefix\n", translate(prefix, LOC(f->locale, prefix))); } - show_allies_cr(F, f, g->allies); + show_allies_cr(F, f, g); } } diff --git a/src/creport.test.c b/src/creport.test.c index bacf8def0..b536a7114 100644 --- a/src/creport.test.c +++ b/src/creport.test.c @@ -3,7 +3,6 @@ #include "move.h" #include "spy.h" #include "travelthru.h" -#include "keyword.h" #include #include @@ -17,6 +16,7 @@ #include #include +#include "util/keyword.h" #include #include #include @@ -227,7 +227,6 @@ static void test_cr_factionstealth(CuTest *tc) { faction *f1, *f2; region *r; unit *u; - ally *al; test_setup(); f1 = test_create_faction(NULL); @@ -298,8 +297,7 @@ static void test_cr_factionstealth(CuTest *tc) { mstream_done(&strm); /* we see the same thing as them when we are an ally */ - al = ally_add(&f1->allies, f2); - al->status = HELP_FSTEALTH; + ally_set(&f1->allies, f2, HELP_FSTEALTH); mstream_init(&strm); cr_output_unit(&strm, f2, u, seen_unit); CuAssertIntEquals(tc, f1->no, cr_get_int(&strm, ";Partei", -1)); diff --git a/src/economy.c b/src/economy.c index baba6c1ac..1d3f6685f 100644 --- a/src/economy.c +++ b/src/economy.c @@ -20,7 +20,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #ifdef _MSC_VER #include #endif -#include + #include "economy.h" #include "alchemy.h" @@ -45,10 +45,13 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* kernel includes */ #include "kernel/ally.h" +#include "kernel/attrib.h" #include "kernel/building.h" #include "kernel/calendar.h" +#include "kernel/config.h" #include "kernel/curse.h" #include "kernel/equipment.h" +#include "kernel/event.h" #include "kernel/faction.h" #include "kernel/item.h" #include "kernel/messages.h" @@ -64,13 +67,12 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "kernel/unit.h" /* util includes */ -#include #include -#include #include #include #include #include +#include "util/param.h" #include #include @@ -103,6 +105,8 @@ static void recruit_init(void) } } +#define ENTERTAINFRACTION 20 + int entertainmoney(const region * r) { double n; @@ -978,11 +982,6 @@ static void allocate_resource(unit * u, const resource_type * rtype, int want) } } - if (besieged(u)) { - cmistake(u, u->thisorder, 60, MSG_PRODUCE); - return; - } - if (rtype->modifiers) { message *msg = get_modifiers(u, sk, rtype, &save_mod, &skill_mod); if (msg) { @@ -1604,11 +1603,6 @@ static void buy(unit * u, econ_request ** buyorders, struct order *ord) cmistake(u, ord, 26, MSG_COMMERCE); return; } - if (besieged(u)) { - /* Belagerte Einheiten k�nnen nichts kaufen. */ - cmistake(u, ord, 60, MSG_COMMERCE); - return; - } /* Entweder man ist Insekt in Sumpf/Wueste, oder es muss * einen Handelsposten in der Region geben: */ @@ -1928,12 +1922,6 @@ static bool sell(unit * u, econ_request ** sellorders, struct order *ord) return false; } } - /* Belagerte Einheiten k�nnen nichts verkaufen. */ - - if (besieged(u)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error60", "")); - return false; - } /* In der Region mu� es eine Burg geben. */ if (u_race(u) == get_race(RC_INSECT)) { @@ -2407,10 +2395,6 @@ void entertain_cmd(unit * u, struct order *ord) cmistake(u, ord, 58, MSG_INCOME); return; } - if (besieged(u)) { - cmistake(u, ord, 60, MSG_INCOME); - return; - } if (u->ship && is_guarded(r, u)) { cmistake(u, ord, 69, MSG_INCOME); return; @@ -2499,11 +2483,6 @@ static int do_work(unit * u, order * ord, econ_request * o) cmistake(u, ord, 313, MSG_INCOME); return -1; } - if (besieged(u)) { - if (ord) - cmistake(u, ord, 60, MSG_INCOME); - return -1; - } if (u->ship && is_guarded(r, u)) { if (ord) cmistake(u, ord, 69, MSG_INCOME); @@ -2612,10 +2591,6 @@ void tax_cmd(unit * u, struct order *ord, econ_request ** taxorders) return; } - if (besieged(u)) { - cmistake(u, ord, 60, MSG_INCOME); - return; - } n = armedmen(u, false); if (!n) { @@ -2686,10 +2661,6 @@ void loot_cmd(unit * u, struct order *ord, econ_request ** lootorders) return; } - if (besieged(u)) { - cmistake(u, ord, 60, MSG_INCOME); - return; - } n = armedmen(u, false); if (!n) { diff --git a/src/economy.test.c b/src/economy.test.c index 12fff57f8..236c181c5 100644 --- a/src/economy.test.c +++ b/src/economy.test.c @@ -19,7 +19,7 @@ #include #include -#include +#include #include #include @@ -358,7 +358,7 @@ static void test_tax_cmd(CuTest *tc) { set_level(u, SK_TAXING, 1); tax_cmd(u, ord, &taxorders); - CuAssertPtrEquals(tc, 0, test_find_messagetype(u->faction->msgs, "error_no_tax_skill")); + CuAssertPtrEquals(tc, NULL, test_find_messagetype(u->faction->msgs, "error_no_tax_skill")); CuAssertPtrNotNull(tc, taxorders); rsetmoney(r, 11); @@ -416,8 +416,8 @@ static void test_maintain_buildings(CuTest *tc) { b->flags = 0; maintain_buildings(r); CuAssertIntEquals(tc, BLD_MAINTAINED, fval(b, BLD_MAINTAINED)); - CuAssertPtrEquals(tc, 0, f->msgs); - CuAssertPtrEquals(tc, 0, r->msgs); + CuAssertPtrEquals(tc, NULL, f->msgs); + CuAssertPtrEquals(tc, NULL, r->msgs); req = calloc(2, sizeof(maintenance)); req[0].number = 100; @@ -439,8 +439,8 @@ static void test_maintain_buildings(CuTest *tc) { maintain_buildings(r); CuAssertIntEquals(tc, BLD_MAINTAINED, fval(b, BLD_MAINTAINED)); CuAssertIntEquals(tc, 0, i_get(u->items, itype)); - CuAssertPtrEquals(tc, 0, r->msgs); - CuAssertPtrEquals(tc, 0, test_find_messagetype(f->msgs, "maintenance_nowork")); + CuAssertPtrEquals(tc, NULL, r->msgs); + CuAssertPtrEquals(tc, NULL, test_find_messagetype(f->msgs, "maintenance_nowork")); CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "maintenance")); test_clear_messagelist(&f->msgs); @@ -449,7 +449,7 @@ static void test_maintain_buildings(CuTest *tc) { b->flags = 0; maintain_buildings(r); CuAssertIntEquals(tc, 0, fval(b, BLD_MAINTAINED)); - CuAssertPtrEquals(tc, 0, f->msgs); + CuAssertPtrEquals(tc, NULL, f->msgs); CuAssertPtrNotNull(tc, test_find_messagetype(r->msgs, "maintenance_noowner")); test_clear_messagelist(&r->msgs); @@ -488,6 +488,7 @@ static void test_recruit_insect(CuTest *tc) { test_setup(); test_create_calendar(); + test_create_terrain("desert", -1); f = test_create_faction(test_create_race("insect")); u = test_create_unit(f, test_create_region(0, 0, NULL)); u->thisorder = create_order(K_RECRUIT, f->locale, "%d", 1); diff --git a/src/eressea.c b/src/eressea.c index 0bf1454ee..8e7da7f7a 100644 --- a/src/eressea.c +++ b/src/eressea.c @@ -1,14 +1,14 @@ #include #include "eressea.h" +#include "kernel/building.h" #include "kernel/calendar.h" +#include "kernel/database.h" #include "kernel/config.h" #include "kernel/curse.h" -#include "kernel/faction.h" -#include "kernel/building.h" #include "kernel/equipment.h" +#include "kernel/faction.h" #include "kernel/item.h" -#include "kernel/database.h" #include "util/functions.h" #include "util/language.h" @@ -54,12 +54,12 @@ void game_done(void) free_locales(); #endif kernel_done(); - dblib_close(); + swapdb_close(); } void game_init(void) { - dblib_open(); + swapdb_open(); errno = 0; kernel_init(); register_triggers(); diff --git a/src/gamedb.c b/src/gamedb.c new file mode 100644 index 000000000..5f53d9120 --- /dev/null +++ b/src/gamedb.c @@ -0,0 +1,33 @@ +#ifdef _MSC_VER +#include +#endif + +#include "gamedb.h" + +#include "kernel/config.h" +#include "kernel/calendar.h" +#include "kernel/faction.h" +#include "kernel/db/driver.h" + +int gamedb_update(void) +{ + faction *f; + int err; + const char *dbname; + + dbname = config_get("game.dbname"); + + err = db_driver_open(DB_GAME, dbname); + if (err == 0) { + for (f = factions; f; f = f->next) { + int uid = db_driver_faction_save(f->uid, f->no, turn, + faction_getemail(f), + faction_getpassword(f)); + if (uid > 0) { + f->uid = uid; + } + } + db_driver_close(DB_GAME); + } + return err; +} diff --git a/src/gamedb.h b/src/gamedb.h new file mode 100644 index 000000000..01251f356 --- /dev/null +++ b/src/gamedb.h @@ -0,0 +1,3 @@ +#pragma once + +int gamedb_update(void); diff --git a/src/give.c b/src/give.c index c47f9b9e2..60b728479 100644 --- a/src/give.c +++ b/src/give.c @@ -16,6 +16,7 @@ #include #include "give.h" +#include "contact.h" #include "economy.h" #include "laws.h" @@ -25,6 +26,8 @@ #include /* kernel includes */ +#include +#include #include #include #include @@ -41,11 +44,10 @@ #include /* util includes */ -#include #include -#include #include #include +#include #include /* libc includes */ @@ -585,14 +587,12 @@ void give_unit(unit * u, unit * u2, order * ord) } } if (has_skill(u, SK_MAGIC)) { - sc_mage *mage; if (count_skill(u2->faction, SK_MAGIC) + u->number > skill_limit(u2->faction, SK_MAGIC)) { cmistake(u, ord, 155, MSG_COMMERCE); return; } - mage = get_mage_depr(u); - if (!mage || u2->faction->magiegebiet != mage->magietyp) { + if (u2->faction->magiegebiet != unit_get_magic(u)) { cmistake(u, ord, 157, MSG_COMMERCE); return; } diff --git a/src/give.test.c b/src/give.test.c index 3f6ffa40a..c62973388 100644 --- a/src/give.test.c +++ b/src/give.test.c @@ -1,6 +1,8 @@ #include #include "give.h" + +#include "contact.h" #include "economy.h" #include @@ -16,6 +18,7 @@ #include #include #include +#include #include #include @@ -43,8 +46,7 @@ static void setup_give(struct give *env) { env->itype = it_get_or_create(rt_get_or_create("money")); env->itype->flags |= ITF_HERB; if (env->f2) { - ally * al = ally_add(&env->f2->allies, env->f1); - al->status = HELP_GIVE; + ally_set(&env->f2->allies, env->f1, HELP_GIVE); env->dst = test_create_unit(env->f2, env->r); } else { @@ -193,7 +195,7 @@ static void test_give_men_limit(CuTest * tc) { config_set("rules.give.max_men", "1"); /* below the limit, give men, increase newbies counter */ - usetcontact(env.dst, env.src); + contact_unit(env.dst, env.src); msg = give_men(1, env.src, env.dst, NULL); CuAssertStrEquals(tc, "give_person", test_get_messagetype(msg)); CuAssertIntEquals(tc, 2, env.dst->number); @@ -202,7 +204,7 @@ static void test_give_men_limit(CuTest * tc) { msg_release(msg); /* beyond the limit, do nothing */ - usetcontact(env.src, env.dst); + contact_unit(env.src, env.dst); msg = give_men(2, env.dst, env.src, NULL); CuAssertStrEquals(tc, "error129", test_get_messagetype(msg)); CuAssertIntEquals(tc, 2, env.dst->number); @@ -281,7 +283,7 @@ static void test_give_men_other_faction(CuTest * tc) { env.f1 = test_create_faction(NULL); env.f2 = test_create_faction(NULL); setup_give(&env); - usetcontact(env.dst, env.src); + contact_unit(env.dst, env.src); msg = give_men(1, env.src, env.dst, NULL); CuAssertStrEquals(tc, "give_person", test_get_messagetype(msg)); CuAssertIntEquals(tc, 2, env.dst->number); diff --git a/src/gmtool.c b/src/gmtool.c index 757841af6..3b7aed36a 100644 --- a/src/gmtool.c +++ b/src/gmtool.c @@ -14,55 +14,44 @@ #include -#include - #include "gmtool.h" +#include "direction.h" -#include -#include -#include #include #include "kernel/building.h" -#include "kernel/calendar.h" +#include "kernel/config.h" #include "kernel/faction.h" #include "kernel/item.h" #include "kernel/plane.h" -#include "kernel/race.h" #include "kernel/region.h" +#include "kernel/resources.h" #include "kernel/terrainid.h" #include "kernel/unit.h" -#include "kernel/resources.h" #include "kernel/save.h" #include "kernel/ship.h" #include "kernel/terrain.h" -#include -#include - -#include +#include #include #include -#include #include -#include -#include -#include -#include +#include "util/path.h" +#include "util/rand.h" +#include "util/rng.h" +#include "util/unicode.h" #include "gmtool_structs.h" #include "console.h" #include "listbox.h" -#include "wormhole.h" #include "teleport.h" #include -#include -#include #include -#include +#include #include +#include #include #include @@ -1076,20 +1065,10 @@ static void seed_player(state *st, const newfaction *player) { pnormalize(&nx, &ny, st->cursor.pl); r = findregion(nx, ny); if (r) { - const char *at = strchr(player->email, '@'); faction *f; - addplayer(r, f = addfaction(player->email, player->password, - player->race, player->lang, - player->subscription)); - if (at) { - char fname[64]; - size_t len = at - player->email; - if (len>4 && lenemail, len); - fname[len]=0; - faction_setname(f, fname); - } - } + const char *password = player->password ? player->password : itoa36(rng_int()); + addplayer(r, f = addfaction(player->email, password, + player->race, player->lang)); } } } @@ -1534,7 +1513,7 @@ static void update_view(view * vi) state *state_open(void) { - state *st = calloc(sizeof(state), 1); + state *st = (state *)calloc(1, sizeof(state)); st->display.pl = get_homeplane(); st->cursor.pl = get_homeplane(); st->cursor.x = 0; diff --git a/src/guard.c b/src/guard.c index 118ede5fc..437980b34 100644 --- a/src/guard.c +++ b/src/guard.c @@ -20,6 +20,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include "guard.h" + +#include "contact.h" #include "laws.h" #include "monsters.h" @@ -105,8 +107,6 @@ static bool is_guardian_r(const unit * guard) { if (guard->number == 0) return false; - if (besieged(guard)) - return false; /* if region_owners exist then they may be guardians: */ if (guard->building && rule_region_owners() && guard == building_owner(guard->building)) { diff --git a/src/guard.test.c b/src/guard.test.c index 6264aad21..1c4da2d1f 100644 --- a/src/guard.test.c +++ b/src/guard.test.c @@ -29,7 +29,7 @@ static void test_is_guarded(CuTest *tc) { r = test_create_region(0, 0, NULL); u1 = test_create_unit(test_create_faction(NULL), r); u2 = test_create_unit(test_create_faction(rc), r); - CuAssertPtrEquals(tc, 0, is_guarded(r, u1)); + CuAssertPtrEquals(tc, NULL, is_guarded(r, u1)); setguard(u2, true); CuAssertPtrEquals(tc, u2, is_guarded(r, u1)); test_teardown(); diff --git a/src/helpers.c b/src/helpers.c index 8acabd97c..7f19a6dcc 100644 --- a/src/helpers.c +++ b/src/helpers.c @@ -17,26 +17,21 @@ without prior permission by the authors of Eressea. #include "helpers.h" #include "vortex.h" #include "alchemy.h" +#include "magic.h" -#include -#include -#include +#include +#include #include -#include +#include #include #include #include -#include +#include -#include #include #include -#include #include -#include -#include #include -#include #include #include @@ -46,8 +41,10 @@ without prior permission by the authors of Eressea. #include #include -#include -#include +#include +#include + +struct order; static int lua_giveitem(unit * s, unit * d, const item_type * itype, int n, struct order *ord) @@ -181,7 +178,7 @@ static bool lua_equipunit(unit *u, const char *eqname, int mask) { lua_pop(L, 1); } else { - result = (bool)lua_toboolean(L, -1); + result = lua_toboolean(L, -1) != 0; lua_pop(L, 1); } } diff --git a/src/helpers.h b/src/helpers.h index d0bbcc58b..a5eccd0f5 100644 --- a/src/helpers.h +++ b/src/helpers.h @@ -14,8 +14,6 @@ without prior permission by the authors of Eressea. extern "C" { #endif - struct lua_State; - void register_tolua_helpers(void); #ifdef __cplusplus diff --git a/src/items.c b/src/items.c index 574c1da3b..72bd6d713 100644 --- a/src/items.c +++ b/src/items.c @@ -5,7 +5,6 @@ #include "alchemy.h" #include "skill.h" -#include "keyword.h" #include "direction.h" #include "study.h" #include "economy.h" @@ -33,8 +32,9 @@ #include #include -#include -#include +#include +#include +#include #include #include #include diff --git a/src/items/speedsail.c b/src/items/speedsail.c index b224d6d6d..e6d3d1386 100644 --- a/src/items/speedsail.c +++ b/src/items/speedsail.c @@ -31,7 +31,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include /* util includes */ -#include +#include #include #include diff --git a/src/items/xerewards.c b/src/items/xerewards.c index 71746bbf3..d039a19a1 100644 --- a/src/items/xerewards.c +++ b/src/items/xerewards.c @@ -74,7 +74,7 @@ use_manacrystal(struct unit *u, const struct item_type *itype, int amount, return -1; } - msp = max_spellpoints(u->region, u) / 2; + msp = max_spellpoints_depr(u->region, u) / 2; for (i = 0; i != amount; ++i) { sp += MAX(25, msp); change_spellpoints(u, sp); diff --git a/src/items/xerewards.test.c b/src/items/xerewards.test.c index dc9aa2621..d135b27fb 100644 --- a/src/items/xerewards.test.c +++ b/src/items/xerewards.test.c @@ -25,7 +25,7 @@ static void test_manacrystal(CuTest *tc) { CuAssertIntEquals(tc, -1, use_manacrystal(u, itype, 1, NULL)); CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "error295")); test_clear_messages(u->faction); - create_mage(u, M_GRAY); + create_mage(u, M_GWYRRD); set_level(u, SK_MAGIC, 5); CuAssertIntEquals(tc, 0, get_spellpoints(u)); CuAssertIntEquals(tc, 1, use_manacrystal(u, itype, 1, NULL)); diff --git a/src/json.test.c b/src/json.test.c index 48a5e4be6..30d4e072e 100644 --- a/src/json.test.c +++ b/src/json.test.c @@ -71,8 +71,8 @@ static cJSON *export_a_region(CuTest * tc, const struct terrain_type *terrain, r json = cJSON_Parse(buf); CuAssertPtrNotNull(tc, json); CuAssertIntEquals(tc, cJSON_Object, json->type); - CuAssertPtrEquals(tc, 0, cJSON_GetObjectItem(json, "factions")); - CuAssertPtrEquals(tc, 0, cJSON_GetObjectItem(json, "units")); + CuAssertPtrEquals(tc, NULL, cJSON_GetObjectItem(json, "factions")); + CuAssertPtrEquals(tc, NULL, cJSON_GetObjectItem(json, "units")); CuAssertPtrNotNull(tc, regs = cJSON_GetObjectItem(json, "regions")); CuAssertIntEquals(tc, cJSON_Object, regs->type); result = regs->child; @@ -111,7 +111,7 @@ static void test_export_ocean_region(CuTest * tc) { test_setup(); terrain = test_create_terrain("ocean", SEA_REGION); json = export_a_region(tc, terrain, 0); - CuAssertPtrEquals(tc, 0, cJSON_GetObjectItem(json, "name")); + CuAssertPtrEquals(tc, NULL, cJSON_GetObjectItem(json, "name")); cJSON_Delete(json); test_teardown(); } diff --git a/src/jsonconf.c b/src/jsonconf.c index fcd6f5c78..ff442f990 100644 --- a/src/jsonconf.c +++ b/src/jsonconf.c @@ -29,9 +29,10 @@ without prior permission by the authors of Eressea. #include "kernel/spellbook.h" /* util includes */ -#include "util/attrib.h" +#include "kernel/attrib.h" #include "util/crmessage.h" #include "util/functions.h" +#include "util/keyword.h" #include "util/language.h" #include "util/log.h" #include "util/message.h" @@ -42,7 +43,6 @@ without prior permission by the authors of Eressea. /* game modules */ #include "direction.h" -#include "keyword.h" #include "move.h" #include "prefix.h" #include "skill.h" @@ -846,7 +846,7 @@ static void json_keyword(cJSON *json, struct locale *lang) { } for (child = json->child; child; child = child->next) { keyword_t kwd = findkeyword(child->string); - if (kwd != NOKEYWORD) { + if (kwd != NOKEYWORD && keywords[kwd]) { if (child->type == cJSON_String) { init_keyword(lang, kwd, child->valuestring); locale_setstring(lang, mkname("keyword", keywords[kwd]), child->valuestring); diff --git a/src/jsonconf.test.c b/src/jsonconf.test.c index 7c15b63f1..1fc27d3e6 100644 --- a/src/jsonconf.test.c +++ b/src/jsonconf.test.c @@ -15,11 +15,11 @@ #include "kernel/order.h" #include "kernel/terrain.h" +#include "util/keyword.h" #include "util/language.h" #include "kernel/calendar.h" #include "direction.h" -#include "keyword.h" #include "move.h" #include "prefix.h" @@ -120,7 +120,7 @@ static void test_disable(CuTest * tc) const char * data = "{\"disabled\": [ " "\"alchemy\"," "\"pay\"," - "\"besiege\"," + "\"attack\"," "\"module\"" "]}"; cJSON *json = cJSON_Parse(data); @@ -129,13 +129,13 @@ static void test_disable(CuTest * tc) CuAssertTrue(tc, skill_enabled(SK_ALCHEMY)); CuAssertTrue(tc, !keyword_disabled(K_BANNER)); CuAssertTrue(tc, !keyword_disabled(K_PAY)); - CuAssertTrue(tc, !keyword_disabled(K_BESIEGE)); + CuAssertTrue(tc, !keyword_disabled(K_ATTACK)); CuAssertIntEquals(tc, 1, config_get_int("module.enabled", 1)); json_config(json); CuAssertTrue(tc, !skill_enabled(SK_ALCHEMY)); CuAssertTrue(tc, !keyword_disabled(K_BANNER)); CuAssertTrue(tc, keyword_disabled(K_PAY)); - CuAssertTrue(tc, keyword_disabled(K_BESIEGE)); + CuAssertTrue(tc, keyword_disabled(K_ATTACK)); CuAssertIntEquals(tc, 0, config_get_int("module.enabled", 1)); cJSON_Delete(json); test_teardown(); diff --git a/src/kernel/CMakeLists.txt b/src/kernel/CMakeLists.txt index 86c2fb90c..dcd19c35a 100644 --- a/src/kernel/CMakeLists.txt +++ b/src/kernel/CMakeLists.txt @@ -1,9 +1,18 @@ cmake_minimum_required(VERSION 2.6) project(kernel C) +SET(_DBFILES db/memory.c) + +IF(SQLITE3_FOUND) +SET(_DBFILES db/sqlite.c) +ELSEIF(DB_FOUND) +SET(_DBFILES db/berkeley.c) +ENDIF(SQLITE3_FOUND) + SET(_TEST_FILES alliance.test.c ally.test.c +attrib.test.c build.test.c building.test.c # callbacks.test.c @@ -14,12 +23,13 @@ config.test.c curse.test.c database.test.c equipment.test.c +# event.test.c faction.test.c +gamedata.test.c group.test.c item.test.c messages.test.c order.test.c -orderdb.test.c # pathfinder.test.c plane.test.c pool.test.c @@ -35,18 +45,11 @@ spell.test.c unit.test.c ) -SET(_DBFILES db/critbit.c) - -IF(SQLITE3_FOUND) -SET(_DBFILES db/sqlite.c) -ELSEIF(DB_FOUND) -SET(_DBFILES db/berkeley.c) -ENDIF(SQLITE3_FOUND) - SET(_FILES ${_DBFILES} alliance.c ally.c +attrib.c build.c building.c callbacks.c @@ -57,12 +60,13 @@ connection.c curse.c database.c equipment.c +event.c faction.c +gamedata.c group.c item.c messages.c order.c -orderdb.c pathfinder.c plane.c pool.c diff --git a/src/kernel/alliance.c b/src/kernel/alliance.c index d5dda0143..1996c5aad 100644 --- a/src/kernel/alliance.c +++ b/src/kernel/alliance.c @@ -27,7 +27,7 @@ without prior permission by the authors of Eressea. #include /* util includes */ -#include +#include #include #include #include diff --git a/src/kernel/alliance.test.c b/src/kernel/alliance.test.c index 00fe1f4d9..284d57d27 100644 --- a/src/kernel/alliance.test.c +++ b/src/kernel/alliance.test.c @@ -34,14 +34,14 @@ static void test_alliance_make(CuTest *tc) { CuAssertStrEquals(tc, "Hodor", al->name); CuAssertIntEquals(tc, 1, al->id); CuAssertIntEquals(tc, 0, al->flags); - CuAssertPtrEquals(tc, 0, al->members); - CuAssertPtrEquals(tc, 0, al->_leader); - CuAssertPtrEquals(tc, 0, al->allies); + CuAssertPtrEquals(tc, NULL, al->members); + CuAssertPtrEquals(tc, NULL, al->_leader); + CuAssertPtrEquals(tc, NULL, al->allies); CuAssertPtrEquals(tc, al, findalliance(1)); CuAssertPtrEquals(tc, al, alliances); free_alliances(); - CuAssertPtrEquals(tc, 0, findalliance(1)); - CuAssertPtrEquals(tc, 0, alliances); + CuAssertPtrEquals(tc, NULL, findalliance(1)); + CuAssertPtrEquals(tc, NULL, alliances); test_teardown(); } @@ -50,8 +50,8 @@ static void test_alliance_join(CuTest *tc) { alliance * al; setup_alliance(&fix); - CuAssertPtrEquals(tc, 0, fix.f1->alliance); - CuAssertPtrEquals(tc, 0, fix.f2->alliance); + CuAssertPtrEquals(tc, NULL, fix.f1->alliance); + CuAssertPtrEquals(tc, NULL, fix.f2->alliance); al = makealliance(1, "Hodor"); setalliance(fix.f1, al); CuAssertPtrEquals(tc, fix.f1, alliance_get_leader(al)); @@ -99,7 +99,7 @@ static void test_alliance_cmd(CuTest *tc) { unit_addorder(u2, create_order(K_ALLIANCE, u1->faction->locale, "%s %s", alliance_kwd[ALLIANCE_JOIN], itoa36(42))); CuAssertTrue(tc, is_allied(u1->faction, u1->faction)); CuAssertTrue(tc, !is_allied(u1->faction, u2->faction)); - CuAssertPtrEquals(tc, 0, f_get_alliance(u1->faction)); + CuAssertPtrEquals(tc, NULL, f_get_alliance(u1->faction)); alliance_cmd(); al = f_get_alliance(u1->faction); CuAssertPtrNotNull(tc, al); @@ -126,10 +126,10 @@ static void test_alliance_limits(CuTest *tc) { 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)); + CuAssertPtrEquals(tc, NULL, f_get_alliance(u1->faction)); alliance_cmd(); CuAssertPtrNotNull(tc, f_get_alliance(u1->faction)); - CuAssertPtrEquals(tc, 0, f_get_alliance(u2->faction)); + CuAssertPtrEquals(tc, NULL, 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_teardown(); @@ -152,7 +152,7 @@ static void test_alliance_cmd_kick(CuTest *tc) { CuAssertTrue(tc, is_allied(u1->faction, u2->faction)); alliance_cmd(); CuAssertTrue(tc, !is_allied(u1->faction, u2->faction)); - CuAssertPtrEquals(tc, 0, f_get_alliance(u2->faction)); + CuAssertPtrEquals(tc, NULL, f_get_alliance(u2->faction)); test_teardown(); } @@ -168,10 +168,10 @@ static void test_alliance_cmd_no_invite(CuTest *tc) { unit_addorder(u2, create_order(K_ALLIANCE, u1->faction->locale, "%s %s", alliance_kwd[ALLIANCE_JOIN], itoa36(42))); CuAssertTrue(tc, is_allied(u1->faction, u1->faction)); CuAssertTrue(tc, !is_allied(u1->faction, u2->faction)); - CuAssertPtrEquals(tc, 0, f_get_alliance(u1->faction)); + CuAssertPtrEquals(tc, NULL, f_get_alliance(u1->faction)); alliance_cmd(); CuAssertPtrNotNull(tc, f_get_alliance(u1->faction)); - CuAssertPtrEquals(tc, 0, f_get_alliance(u2->faction)); + CuAssertPtrEquals(tc, NULL, f_get_alliance(u2->faction)); CuAssertTrue(tc, !is_allied(u1->faction, u2->faction)); test_teardown(); } @@ -193,7 +193,7 @@ static void test_alliance_cmd_leave(CuTest *tc) { CuAssertTrue(tc, is_allied(u1->faction, u2->faction)); alliance_cmd(); CuAssertTrue(tc, !is_allied(u1->faction, u2->faction)); - CuAssertPtrEquals(tc, 0, f_get_alliance(u1->faction)); + CuAssertPtrEquals(tc, NULL, f_get_alliance(u1->faction)); test_teardown(); } diff --git a/src/kernel/ally.c b/src/kernel/ally.c index 4fadf9c04..80ef6b18f 100644 --- a/src/kernel/ally.c +++ b/src/kernel/ally.c @@ -8,11 +8,10 @@ #include "group.h" #include "faction.h" #include "objtypes.h" -#include "plane.h" -#include +#include #include -#include +#include #include @@ -20,63 +19,146 @@ #include #include -void read_allies(gamedata * data, faction *f) -{ - ally **sfp = &f->allies; - for (;;) { - int aid; - READ_INT(data->store, &aid); - if (aid > 0) { - ally * al = ally_add(sfp, NULL); - int state; - if ((al->faction = findfaction(aid)) == NULL) { - ur_add(RESOLVE_FACTION | aid, (void **)&al->faction, NULL); - } - READ_INT(data->store, &state); - al->status = state & HELP_ALL; - sfp = &al->next; - } - else { - break; - } - } +#define BLOCKSIZE 15 +typedef struct allies { + struct allies *next; + int num; + struct faction *factions[BLOCKSIZE]; + int status[BLOCKSIZE]; +} allies; + +static void block_insert(allies *al, struct faction *f, int status) { + int i = al->num++; + al->status[i] = status; + al->factions[i] = f; + /* TODO: heapify */ } -ally * ally_find(ally *al, const struct faction *f) { - for (; al; al = al->next) { - if (al->faction == f) return al; +static int block_search(allies *al, const struct faction *f) { + int i; + /* TODO: binary search */ + for (i = 0; i != al->num; ++i) { + if (al->factions[i] == f) { + return i; + } + } + return BLOCKSIZE; +} + +int allies_walk(struct allies *all, cb_allies_walk callback, void *udata) +{ + allies *al; + for (al = all; al; al = al->next) { + int i; + for (i = 0; i != al->num; ++i) { + int e = callback(all, al->factions[i], al->status[i], udata); + if (e != 0) { + return e; + } + } } return 0; } -ally * ally_add(ally **al_p, struct faction *f) { - ally * al; - while (*al_p) { - al = *al_p; - if (f && al->faction == f) return al; - al_p = &al->next; +int ally_get(allies *al, const struct faction *f) +{ + for (; al; al = al->next) { + int i = block_search(al, f); + if (i != BLOCKSIZE) { + return al->status[i]; + } } - al = (ally *)malloc(sizeof(ally)); - al->faction = f; - al->status = 0; - al->next = 0; - *al_p = al; - return al; + return 0; } -void ally_remove(ally **al_p, struct faction *f) { - ally * al; - while (*al_p) { - al = *al_p; - if (al->faction == f) { - *al_p = al->next; - free(al); +void ally_set(allies **p_al, struct faction *f, int status) +{ + while (*p_al) { + allies *al = *p_al; + int i = block_search(al, f); + if (i != BLOCKSIZE) { + if (status == 0) { + if (--al->num != i) { + al->factions[i] = al->factions[al->num]; + al->status[i] = al->status[al->num]; + /* TODO: repair heap up or down */ + } + else if (al->num == 0) { + *p_al = al->next; + free(al); + return; + } + } + else { + al->status[i] = status; + } + return; + } + if (al->num < BLOCKSIZE) { + block_insert(al, f, status); + return; + } + p_al = &al->next; + } + *p_al = calloc(1, sizeof(allies)); + block_insert(*p_al, f, status); +} + +void write_allies(gamedata * data, const allies *alist) +{ + const allies *al; + for (al = alist; al; al = al->next) { + int i; + for (i = 0; i != al->num; ++i) { + const faction * f = al->factions[i]; + if (f && f->_alive) { + write_faction_reference(f, data->store); + WRITE_INT(data->store, al->status[i]); + } + } + } + write_faction_reference(NULL, data->store); +} + +void read_allies(gamedata * data, allies **p_al) +{ + for (;;) { + faction *f; + int aid, status; + READ_INT(data->store, &aid); + /* TODO: deal with unresolved factions, somehow */ + if (aid <= 0) { break; } - al_p = &al->next; + f = findfaction(aid); + if (!f) f = faction_create(aid); + READ_INT(data->store, &status); + ally_set(p_al, f, status); } } +void allies_free(allies *al) +{ + while (al) { + allies * an = al->next; + free(al); + al = an; + } +} + +allies *allies_clone(const allies *al) { + allies *al_clone = NULL, **al_end = &al_clone; + + for (; al; al = al->next) { + allies *al_new = calloc(1, sizeof(allies)); + memcpy(al_new, al, sizeof(allies)); + *al_end = al_new; + al_end = &al_new->next; + } + *al_end = NULL; + return al_clone; +} + static int ally_flag(const char *s, int help_mask) { if ((help_mask & HELP_MONEY) && strcmp(s, "money") == 0) @@ -116,26 +198,14 @@ int AllianceAuto(void) } static int -autoalliance(const plane * pl, const faction * sf, const faction * f2) +autoalliance(const faction * sf, const faction * f2) { - if (pl && (pl->flags & PFL_FRIENDLY)) - return HELP_ALL; - - if (f_get_alliance(sf) != NULL && AllianceAuto()) { - if (sf->alliance == f2->alliance) - return AllianceAuto(); + if (sf->alliance == f2->alliance) { + return AllianceAuto(); } - return 0; } -static int ally_mode(const ally * sf, int mode) -{ - if (sf == NULL) - return 0; - return sf->status & mode; -} - static void init_npcfaction(variant *var) { var->i = 1; @@ -160,12 +230,13 @@ attrib_type at_npcfaction = { */ int HelpMask(void) { - static int config, rule = 0; + static int config, rule; if (config_changed(&config)) { const char *str = config_get("rules.help.mask"); if (str != NULL) { char *sstr = str_strdup(str); char *tok = strtok(sstr, " "); + rule = 0; while (tok) { rule |= ally_flag(tok, -1); tok = strtok(NULL, " "); @@ -181,71 +252,79 @@ int HelpMask(void) static int AllianceRestricted(void) { - const char *str = config_get("alliance.restricted"); - int rule = 0; - if (str != NULL) { - char *sstr = str_strdup(str); - char *tok = strtok(sstr, " "); - while (tok) { - rule |= ally_flag(tok, -1); - tok = strtok(NULL, " "); + static int config, rule; + if (config_changed(&config)) { + const char *str = config_get("alliance.restricted"); + rule = 0; + if (str != NULL) { + char *sstr = str_strdup(str); + char *tok = strtok(sstr, " "); + while (tok) { + rule |= ally_flag(tok, -1); + tok = strtok(NULL, " "); + } + free(sstr); } - free(sstr); + rule &= HelpMask(); } - rule &= HelpMask(); return rule; } +int alliance_status(const faction *f, const faction *f2, int status) { + status |= autoalliance(f, f2); + if (status > 0) { + int mask = AllianceRestricted(); + if (mask) { + if (a_find(f->attribs, &at_npcfaction)) { + return status; + } + if (a_find(f2->attribs, &at_npcfaction)) { + return status; + } + if (f->alliance != f2->alliance) { + status &= ~mask; + } + } + } + return status; +} + int -alliedgroup(const struct plane *pl, const struct faction *f, - const struct faction *f2, const struct ally *sf, int mode) +alliedgroup(const struct faction *f, + const struct faction *f2, const struct group *g, int mask) { + allies *all = g ? g->allies : f->allies; + int status; + if (!(faction_alive(f) && faction_alive(f2))) { return 0; } - while (sf && sf->faction != f2) { - sf = sf->next; - } - if (sf == NULL) { - mode = mode & autoalliance(pl, f, f2); - } - mode = ally_mode(sf, mode) | (mode & autoalliance(pl, f, f2)); - if (AllianceRestricted()) { - if (a_find(f->attribs, &at_npcfaction)) { - return mode; - } - if (a_find(f2->attribs, &at_npcfaction)) { - return mode; - } - if (f->alliance != f2->alliance) { - mode &= ~AllianceRestricted(); - } - } - return mode; + status = ally_get(all, f2) & mask; + return alliance_status(f, f2, status); } int -alliedfaction(const struct plane *pl, const struct faction *f, - const struct faction *f2, int mode) +alliedfaction(const struct faction *f, const struct faction *f2, int mask) { - return alliedgroup(pl, f, f2, f->allies, mode); + return alliedgroup(f, f2, NULL, mask); } /* Die Gruppe von Einheit u hat helfe zu f2 gesetzt. */ -int alliedunit(const unit * u, const faction * f2, int mode) +int alliedunit(const unit * u, const faction * f2, int mask) { - int automode; - assert(u); assert(f2); assert(u->region); /* the unit should be in a region, but it's possible that u->number==0 (TEMP units) */ - if (u->faction == f2) - return mode; + if (u->faction == f2) { + return mask; + } + if (!faction_alive(f2)) { + return 0; + } if (u->faction != NULL && f2 != NULL) { - ally *sf; - plane *pl; + group *g; - if (mode & HELP_FIGHT) { + if (mask & HELP_FIGHT) { if ((u->flags & UFL_DEFENDER) || (u->faction->flags & FFL_DEFENDER)) { faction *owner = region_get_owner(u->region); /* helps the owner of the region */ @@ -255,19 +334,11 @@ int alliedunit(const unit * u, const faction * f2, int mode) } } - pl = rplane(u->region); - automode = mode & autoalliance(pl, u->faction, f2); - - if (pl != NULL && (pl->flags & PFL_NOALLIANCES)) - mode = (mode & automode) | (mode & HELP_GIVE); - - sf = u->faction->allies; - if (fval(u, UFL_GROUP)) { - const attrib *a = a_find(u->attribs, &at_group); - if (a != NULL) - sf = ((group *)a->data.v)->allies; + g = get_group(u); + if (g) { + return alliedgroup(u->faction, f2, g, mask); } - return alliedgroup(pl, u->faction, f2, sf, mode); + return alliedfaction(u->faction, f2, mask); } return 0; } diff --git a/src/kernel/ally.h b/src/kernel/ally.h index d4c41d36c..3d9058bc4 100644 --- a/src/kernel/ally.h +++ b/src/kernel/ally.h @@ -23,33 +23,35 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif - struct attrib_type; - struct plane; - struct faction; - struct gamedata; - struct unit; +struct attrib_type; +struct faction; +struct group; +struct gamedata; +struct unit; +struct allies; - extern struct attrib_type at_npcfaction; +extern struct attrib_type at_npcfaction; - typedef struct ally { - struct ally *next; - struct faction *faction; - int status; - } ally; +int ally_get(struct allies *al, const struct faction *f); +void ally_set(struct allies **p_al, struct faction *f, int status); +void write_allies(struct gamedata * data, const struct allies *alist); +void read_allies(struct gamedata * data, struct allies **sfp); +typedef int (*cb_allies_walk)(struct allies *, struct faction *, int, void *); +int allies_walk(struct allies *allies, cb_allies_walk callback, void *udata); +struct allies *allies_clone(const struct allies *al); - void read_allies(struct gamedata * data, struct faction *f); - ally * ally_find(ally *al, const struct faction *f); - ally * ally_add(ally **al_p, struct faction *f); - void ally_remove(ally **al_p, struct faction *f); +void allies_free(struct allies *al); int AllianceAuto(void); /* flags that allied factions get automatically */ int HelpMask(void); /* flags restricted to allied factions */ int alliedunit(const struct unit *u, const struct faction *f2, - int mode); - int alliedfaction(const struct plane *pl, const struct faction *f, - const struct faction *f2, int mode); - int alliedgroup(const struct plane *pl, const struct faction *f, - const struct faction *f2, const struct ally *sf, int mode); + int mask); + + int alliedfaction(const struct faction *f, const struct faction *f2, + int mask); + int alliedgroup(const struct faction *f, const struct faction *f2, + const struct group *g, int mask); + int alliance_status(const struct faction *f, const struct faction *f2, int status); #ifdef __cplusplus } diff --git a/src/kernel/ally.test.c b/src/kernel/ally.test.c index 66542a298..248eb5831 100644 --- a/src/kernel/ally.test.c +++ b/src/kernel/ally.test.c @@ -5,39 +5,47 @@ #include #include -static void test_ally(CuTest * tc) +static void test_allies_clone(CuTest * tc) { - ally * al = 0; - struct faction * f1 = test_create_faction(NULL); + struct allies * al = NULL, *ac; + struct faction * f; - ally_add(&al, f1); - CuAssertPtrNotNull(tc, al); - CuAssertPtrEquals(tc, f1, ally_find(al, f1)->faction); - - ally_remove(&al, f1); - CuAssertPtrEquals(tc, 0, al); - CuAssertPtrEquals(tc, 0, ally_find(al, f1)); + test_setup(); + f = test_create_faction(NULL); + CuAssertPtrEquals(tc, NULL, allies_clone(NULL)); + + ally_set(&al, f, HELP_GUARD); + ac = allies_clone(al); + CuAssertPtrNotNull(tc, ac); + CuAssertTrue(tc, al != ac); + CuAssertIntEquals(tc, HELP_GUARD, ally_get(ac, f)); + CuAssertIntEquals(tc, HELP_GUARD, ally_get(al, f)); + allies_free(al); + allies_free(ac); + test_teardown(); } -static void test_ally_null(CuTest * tc) -{ - ally *a1 = 0, *a2 = 0; +static void test_allies(CuTest *tc) { + struct allies * al = NULL; + struct faction * f; - a1 = ally_add(&a1, 0); - a2 = ally_add(&a1, 0); - CuAssertPtrNotNull(tc, a1); - CuAssertPtrNotNull(tc, a2); - CuAssertPtrEquals(tc, a2, a1->next); - CuAssertPtrEquals(tc, 0, a2->next); - free(a1); - free(a2); + test_setup(); + f = test_create_faction(NULL); + + CuAssertIntEquals(tc, 0, ally_get(al, f)); + ally_set(&al, f, 42); + CuAssertIntEquals(tc, 42, ally_get(al, f)); + ally_set(&al, f, 0); + CuAssertIntEquals(tc, 0, ally_get(al, f)); + CuAssertPtrEquals(tc, NULL, al); + test_teardown(); } CuSuite *get_ally_suite(void) { CuSuite *suite = CuSuiteNew(); - SUITE_ADD_TEST(suite, test_ally); - SUITE_ADD_TEST(suite, test_ally_null); + SUITE_ADD_TEST(suite, test_allies); + SUITE_ADD_TEST(suite, test_allies_clone); return suite; } diff --git a/src/util/attrib.c b/src/kernel/attrib.c similarity index 99% rename from src/util/attrib.c rename to src/kernel/attrib.c index defb4ff1e..d84a8c8e9 100644 --- a/src/util/attrib.c +++ b/src/kernel/attrib.c @@ -19,12 +19,12 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include "attrib.h" -#include "gamedata.h" -#include "log.h" -#include "variant.h" -#include "storage.h" -#include "strings.h" +#include +#include +#include +#include +#include #include #include diff --git a/src/util/attrib.h b/src/kernel/attrib.h similarity index 99% rename from src/util/attrib.h rename to src/kernel/attrib.h index b7a081d8c..65c41aa71 100644 --- a/src/util/attrib.h +++ b/src/kernel/attrib.h @@ -20,7 +20,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #define ATTRIB_H #include -#include "variant.h" +#include #ifdef __cplusplus extern "C" { #endif diff --git a/src/util/attrib.test.c b/src/kernel/attrib.test.c similarity index 91% rename from src/util/attrib.test.c rename to src/kernel/attrib.test.c index d266196e6..de024c46d 100644 --- a/src/util/attrib.test.c +++ b/src/kernel/attrib.test.c @@ -1,7 +1,7 @@ #include #include "attrib.h" -#include +#include #include #include @@ -15,11 +15,11 @@ static void test_attrib_new(CuTest * tc) attrib_type at_test = { "test" }; attrib * a; CuAssertPtrNotNull(tc, (a = a_new(&at_test))); - CuAssertPtrEquals(tc, 0, a->next); - CuAssertPtrEquals(tc, 0, a->nexttype); + CuAssertPtrEquals(tc, NULL, a->next); + CuAssertPtrEquals(tc, NULL, a->nexttype); CuAssertPtrEquals(tc, (void *)a->type, (void *)&at_test); a_remove(&a, a); - CuAssertPtrEquals(tc, 0, a); + CuAssertPtrEquals(tc, NULL, a); } static void test_attrib_add(CuTest * tc) @@ -51,7 +51,7 @@ static void test_attrib_remove_self(CuTest * tc) { CuAssertPtrNotNull(tc, a_add(&alist, a_new(&at_foo))); CuAssertPtrNotNull(tc, a = a_add(&alist, a_new(&at_foo))); CuAssertPtrEquals(tc, a, alist->next); - CuAssertPtrEquals(tc, 0, alist->nexttype); + CuAssertPtrEquals(tc, NULL, alist->nexttype); CuAssertIntEquals(tc, 1, a_remove(&alist, alist)); CuAssertPtrEquals(tc, a, alist); a_removeall(&alist, NULL); @@ -66,11 +66,11 @@ static void test_attrib_removeall(CuTest * tc) { a_add(&alist, a_new(&at_foo)); a_removeall(&alist, &at_foo); CuAssertPtrEquals(tc, a, alist); - CuAssertPtrEquals(tc, 0, alist->next); + CuAssertPtrEquals(tc, NULL, alist->next); a_add(&alist, a_new(&at_bar)); a_add(&alist, a_new(&at_foo)); a_removeall(&alist, NULL); - CuAssertPtrEquals(tc, 0, alist); + CuAssertPtrEquals(tc, NULL, alist); } static void test_attrib_remove(CuTest * tc) @@ -83,7 +83,7 @@ static void test_attrib_remove(CuTest * tc) CuAssertIntEquals(tc, 1, a_remove(&alist, a)); CuAssertPtrNotNull(tc, alist); CuAssertIntEquals(tc, 1, a_remove(&alist, alist)); - CuAssertPtrEquals(tc, 0, alist); + CuAssertPtrEquals(tc, NULL, alist); } static void test_attrib_nexttype(CuTest * tc) @@ -92,16 +92,16 @@ static void test_attrib_nexttype(CuTest * tc) attrib_type at_bar = { "bar" }; attrib *a, *alist = 0; CuAssertPtrNotNull(tc, (a = a_new(&at_foo))); - CuAssertPtrEquals(tc, 0, a->nexttype); + CuAssertPtrEquals(tc, NULL, a->nexttype); CuAssertPtrEquals(tc, a, a_add(&alist, a)); - CuAssertPtrEquals(tc, 0, alist->nexttype); + CuAssertPtrEquals(tc, NULL, alist->nexttype); CuAssertPtrNotNull(tc, a_add(&alist, a_new(&at_foo))); - CuAssertPtrEquals(tc, 0, alist->nexttype); + CuAssertPtrEquals(tc, NULL, alist->nexttype); CuAssertPtrNotNull(tc, (a = a_add(&alist, a_new(&at_bar)))); CuAssertPtrEquals(tc, a, alist->nexttype); - CuAssertPtrEquals(tc, 0, a->nexttype); + CuAssertPtrEquals(tc, NULL, a->nexttype); a_remove(&alist, alist); CuAssertPtrEquals(tc, a, alist->nexttype); diff --git a/src/kernel/build.c b/src/kernel/build.c index 8b654c45c..c78cf5212 100644 --- a/src/kernel/build.c +++ b/src/kernel/build.c @@ -33,10 +33,12 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* kernel includes */ #include #include -#include +#include #include #include +#include #include +#include #include #include #include @@ -52,17 +54,17 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include /* from libutil */ -#include -#include -#include #include #include #include +#include #include #include +#include /* from libc */ #include +#include #include #include #include @@ -79,7 +81,7 @@ struct building *getbuilding(const struct region *r) ship *getship(const struct region * r) { - ship *sh, *sx = findship(getshipid()); + ship *sh, *sx = findship(getid()); for (sh = r->ships; sh; sh = sh->next) { if (sh == sx) return sh; @@ -179,7 +181,9 @@ int destroy_cmd(unit * u, struct order *ord) s = gettoken(token, sizeof(token)); if (s && *s) { - n = atoi((const char *)s); + ERRNO_CHECK(); + n = atoi(s); + errno = 0; if (n <= 0) { n = INT_MAX; } @@ -279,10 +283,6 @@ void build_road(unit * u, int size, direction_t d) cmistake(u, u->thisorder, 103, MSG_PRODUCE); return; } - if (besieged(u)) { - cmistake(u, u->thisorder, 60, MSG_PRODUCE); - return; - } if (rn == NULL || rn->terrain->max_road < 0) { cmistake(u, u->thisorder, 94, MSG_PRODUCE); @@ -798,11 +798,6 @@ build_building(unit * u, const building_type * btype, int id, int want, order * cmistake(u, ord, 93, MSG_PRODUCE); return 0; } - if (besieged(u)) { - /* units under siege can not build */ - cmistake(u, ord, 60, MSG_PRODUCE); - return 0; - } if (btype->flags & BTF_NOBUILD) { /* special building, cannot be built */ cmistake(u, ord, 221, MSG_PRODUCE); @@ -967,10 +962,6 @@ create_ship(unit * u, const struct ship_type *newtype, int want, cmistake(u, ord, 100, MSG_PRODUCE); return; } - if (besieged(u)) { - cmistake(u, ord, 60, MSG_PRODUCE); - return; - } /* check if skill and material for 1 size is available */ if (effskill(u, cons->skill, 0) < cons->minskill) { diff --git a/src/kernel/build.test.c b/src/kernel/build.test.c index 9de94e0a4..dc360c000 100644 --- a/src/kernel/build.test.c +++ b/src/kernel/build.test.c @@ -1,19 +1,24 @@ +#ifdef _MSC_VER #include -#include +#endif -#include #include "alchemy.h" -#include "types.h" #include "build.h" -#include "guard.h" -#include "order.h" -#include "unit.h" #include "building.h" +#include "config.h" #include "faction.h" -#include "region.h" -#include "race.h" +#include "guard.h" #include "item.h" -#include +#include "messages.h" +#include "order.h" +#include "race.h" +#include "region.h" +#include "types.h" +#include "unit.h" + +#include "util/language.h" +#include "util/param.h" + #include #include @@ -244,8 +249,8 @@ static void test_build_building_no_materials(CuTest *tc) { set_level(u, SK_BUILDING, 1); u->orders = create_order(K_MAKE, u->faction->locale, 0); CuAssertIntEquals(tc, ENOMATERIALS, build_building(u, btype, 0, 4, u->orders)); - CuAssertPtrEquals(tc, 0, u->region->buildings); - CuAssertPtrEquals(tc, 0, u->building); + CuAssertPtrEquals(tc, NULL, u->region->buildings); + CuAssertPtrEquals(tc, NULL, u->building); teardown_build(&bf); } @@ -309,7 +314,7 @@ static void test_build_destroy_road(CuTest *tc) CuAssertIntEquals(tc, 0, destroy_cmd(u, ord)); CuAssertIntEquals(tc, 100, rroad(r, D_EAST)); - CuAssertPtrEquals(tc, 0, test_find_messagetype(f->msgs, "destroy_road")); + CuAssertPtrEquals(tc, NULL, test_find_messagetype(f->msgs, "destroy_road")); set_level(u, SK_ROAD_BUILDING, 1); CuAssertIntEquals(tc, 0, destroy_cmd(u, ord)); @@ -365,7 +370,7 @@ static void test_build_destroy_road_guard(CuTest *tc) CuAssertIntEquals(tc, 0, destroy_cmd(u, ord)); CuAssertIntEquals(tc, 100, rroad(r, D_EAST)); CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error70")); - CuAssertPtrEquals(tc, 0, test_find_messagetype(f->msgs, "destroy_road")); + CuAssertPtrEquals(tc, NULL, test_find_messagetype(f->msgs, "destroy_road")); test_clear_messages(f); setguard(ug, false); diff --git a/src/kernel/building.c b/src/kernel/building.c index 75cad30f7..456ad1704 100644 --- a/src/kernel/building.c +++ b/src/kernel/building.c @@ -38,13 +38,14 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "lighthouse.h" /* util includes */ -#include +#include #include -#include +#include #include -#include +#include #include #include +#include #include #include #include @@ -128,21 +129,13 @@ static void free_buildingtype(void *ptr) { free(btype); } -void free_buildingtypes(void) { - cb_clear(&cb_bldgtypes); - selist_foreach(buildingtypes, free_buildingtype); - selist_free(buildingtypes); - buildingtypes = 0; - ++bt_changes; -} - 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) { - btype = calloc(sizeof(building_type), 1); + btype = (building_type *)calloc(1, sizeof(building_type)); btype->_name = str_strdup(name); btype->flags = BTF_DEFAULT; btype->auraregen = 1.0; @@ -264,17 +257,28 @@ building *findbuilding(int i) static local_names *bnames; -/* Find the building type for a given localized name (as seen by the user). Useful for parsing - * orders. The inverse of locale_string(lang, btype->_name), sort of. */ -const building_type *findbuildingtype(const char *name, - const struct locale *lang) -{ - variant type; - local_names *bn = bnames; +static void free_bnames(void) { + while (bnames) { + local_names *bn = bnames; + bnames = bnames->next; + freetokens(bn->names); + free(bn); + } +} +static local_names *get_bnames(const struct locale *lang) +{ + static int config; + local_names *bn; + + if (bt_changed(&config)) { + free_bnames(); + } + bn = bnames; while (bn) { - if (bn->lang == lang) + if (bn->lang == lang) { break; + } bn = bn->next; } if (!bn) { @@ -291,14 +295,26 @@ const building_type *findbuildingtype(const char *name, const char *n = LOC(lang, btype->_name); if (!n) { log_error("building type %s has no translation in %s", - btype->_name, locale_name(lang)); - } else { + btype->_name, locale_name(lang)); + } + else { + variant type; type.v = (void *)btype; addtoken((struct tnode **)&bn->names, n, type); } } bnames = bn; } + return bn; +} + +/* Find the building type for a given localized name (as seen by the user). Useful for parsing + * orders. The inverse of locale_string(lang, btype->_name), sort of. */ +const building_type *findbuildingtype(const char *name, + const struct locale *lang) +{ + variant type; + local_names *bn = get_bnames(lang); if (findtoken(bn->names, name, &type) == E_TOK_NOMATCH) return NULL; return (const building_type *)type.v; @@ -343,15 +359,14 @@ void resolve_building(building *b) resolve(RESOLVE_BUILDING | b->no, b); } -int read_building_reference(gamedata * data, building **bp, resolve_fun fun) +int read_building_reference(gamedata * data, building **bp) { int id; READ_INT(data->store, &id); if (id > 0) { *bp = findbuilding(id); if (*bp == NULL) { - *bp = NULL; - ur_add(RESOLVE_BUILDING | id, (void**)bp, fun); + *bp = building_create(id); } } else { @@ -360,17 +375,23 @@ int read_building_reference(gamedata * data, building **bp, resolve_fun fun) return id; } +building *building_create(int id) +{ + building *b = (building *)calloc(1, sizeof(building)); + b->no = id; + bhash(b); + return b; +} + building *new_building(const struct building_type * btype, region * r, const struct locale * lang) { building **bptr = &r->buildings; - building *b = (building *)calloc(1, sizeof(building)); + int id = newcontainerid(); + building *b = building_create(id); const char *bname; char buffer[32]; - b->no = newcontainerid(); - bhash(b); - b->type = btype; b->region = r; while (*bptr) @@ -870,3 +891,12 @@ int cmp_current_owner(const building * b, const building * a) } return 0; } + +void free_buildingtypes(void) { + free_bnames(); + cb_clear(&cb_bldgtypes); + selist_foreach(buildingtypes, free_buildingtype); + selist_free(buildingtypes); + buildingtypes = 0; + ++bt_changes; +} diff --git a/src/kernel/building.h b/src/kernel/building.h index eacf42942..a5419325f 100644 --- a/src/kernel/building.h +++ b/src/kernel/building.h @@ -118,7 +118,6 @@ extern "C" { int no; int size; int sizeleft; /* is only used during battle. should be a temporary attribute */ - int besieged; /* should be an attribute */ int flags; } building; @@ -128,8 +127,9 @@ extern "C" { const char *write_buildingname(const building * b, char *ibuf, size_t size); int buildingcapacity(const struct building *b); + struct building *building_create(int id); struct building *new_building(const struct building_type *typ, - struct region *r, const struct locale *lang); + struct region *r, const struct locale *lang); int build_building(struct unit *u, const struct building_type *typ, int id, int size, struct order *ord); bool building_finished(const struct building *b); @@ -167,7 +167,7 @@ extern "C" { void resolve_building(building *b); void write_building_reference(const struct building *b, struct storage *store); - int read_building_reference(struct gamedata * data, struct building **bp, resolve_fun fun); + int read_building_reference(struct gamedata * data, struct building **bp); struct building *findbuilding(int n); diff --git a/src/kernel/command.test.c b/src/kernel/command.test.c index d173474f2..4c7bbb362 100644 --- a/src/kernel/command.test.c +++ b/src/kernel/command.test.c @@ -37,8 +37,8 @@ static void test_command(CuTest * tc) { st = stree_create(); CuAssertPtrNotNull(tc, st); CuAssertPtrEquals(tc, loc, (struct locale *)st->lang); - CuAssertPtrEquals(tc, 0, st->root); - CuAssertPtrEquals(tc, 0, st->next); + CuAssertPtrEquals(tc, NULL, st->root); + CuAssertPtrEquals(tc, NULL, st->next); stree_add(st, "two", parser_two); stree_add(st, "six", parser_six); CuAssertPtrNotNull(tc, st->root); diff --git a/src/kernel/config.c b/src/kernel/config.c index 750d406f6..15387dca7 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -33,7 +33,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "faction.h" #include "group.h" #include "item.h" -#include "keyword.h" #include "messages.h" #include "move.h" #include "objtypes.h" @@ -50,15 +49,18 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "unit.h" /* util includes */ -#include +#include +#include + #include #include -#include +#include #include #include #include #include #include +#include #include #include #include @@ -91,54 +93,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #endif struct settings global; -const char *parameters[MAXPARAMS] = { - "LOCALE", - "ALLES", - "JEDEM", - "BAUERN", - "BURG", - "EINHEIT", - "PRIVAT", - "HINTEN", - "KOMMANDO", - "KRAEUTER", - "NICHT", - "NAECHSTER", - "PARTEI", - "ERESSEA", - "PERSONEN", - "REGION", - "SCHIFF", - "SILBER", - "STRASSEN", - "TEMP", - "FLIEHE", - "GEBAEUDE", - "GIB", /* HELFE GIB */ - "KAEMPFE", - "DURCHREISE", - "BEWACHE", - "ZAUBER", - "PAUSE", - "VORNE", - "AGGRESSIV", - "DEFENSIV", - "STUFE", - "HELFE", - "FREMDES", - "AURA", - "HINTER", - "VOR", - "ANZAHL", - "GEGENSTAENDE", - "TRAENKE", - "GRUPPE", - "PARTEITARNUNG", - "BAEUME", - "ALLIANZ", - "AUTO" -}; - int findoption(const char *s, const struct locale *lang) { void **tokens = get_translations(lang, UT_OPTIONS); @@ -150,78 +104,6 @@ int findoption(const char *s, const struct locale *lang) return NODIRECTION; } -param_t findparam(const char *s, const struct locale * lang) -{ - param_t result = NOPARAM; - char buffer[64]; - char * str = s ? transliterate(buffer, sizeof(buffer) - sizeof(int), s) : 0; - - if (str && *str) { - int i; - void * match; - void **tokens = get_translations(lang, UT_PARAMS); - critbit_tree *cb = (critbit_tree *)*tokens; - if (!cb) { - log_warning("no parameters defined in locale %s", locale_name(lang)); - } - else if (cb_find_prefix(cb, str, strlen(str), &match, 1, 0)) { - cb_get_kv(match, &i, sizeof(int)); - result = (param_t)i; - } - } - return result; -} - -param_t findparam_block(const char *s, const struct locale *lang, bool any_locale) -{ - param_t p; - if (!s || s[0] == '@') { - return NOPARAM; - } - p = findparam(s, lang); - if (any_locale && p==NOPARAM) { - const struct locale *loc; - for (loc=locales;loc;loc=nextlocale(loc)) { - if (loc!=lang) { - p = findparam(s, loc); - if (p==P_FACTION || p==P_GAMENAME) { - break; - } - } - } - } - return p; -} - -param_t findparam_ex(const char *s, const struct locale * lang) -{ - param_t result = findparam(s, lang); - - if (result == NOPARAM) { - const building_type *btype = findbuildingtype(s, lang); - if (btype != NULL) - return P_GEBAEUDE; - } - return (result == P_BUILDING) ? P_GEBAEUDE : result; -} - -bool isparam(const char *s, const struct locale * lang, param_t param) -{ - assert(s); - if (s[0] > '@') { - param_t p = (param == P_GEBAEUDE) ? findparam_ex(s, lang) : findparam(s, lang); - return p == param; - } - return false; -} - -param_t getparam(const struct locale * lang) -{ - char token[64]; - const char *s = gettoken(token, sizeof(token)); - return s ? findparam(s, lang) : NOPARAM; -} - /* -- Erschaffung neuer Einheiten ------------------------------ */ static const char *forbidden[] = { "t", "te", "tem", "temp", NULL }; @@ -267,17 +149,6 @@ int newcontainerid(void) return random_no; } -static const char * parameter_key(int i) -{ - assert(i < MAXPARAMS && i >= 0); - return parameters[i]; -} - -void init_parameters(struct locale *lang) { - init_translations(lang, UT_PARAMS, parameter_key, MAXPARAMS); -} - - void init_terrains_translation(const struct locale *lang) { void **tokens; const terrain_type *terrain; @@ -368,6 +239,7 @@ static void init_magic(struct locale *lang) free(sstr); } } + void init_locale(struct locale *lang) { init_magic(lang); @@ -767,10 +639,6 @@ void free_gamedata(void) free_borders(); free_alliances(); - while (global.attribs) { - a_remove(&global.attribs, global.attribs); - } - while (planes) { plane *pl = planes; planes = planes->next; diff --git a/src/kernel/config.h b/src/kernel/config.h index 94abcb7f4..95df10ae9 100644 --- a/src/kernel/config.h +++ b/src/kernel/config.h @@ -44,12 +44,6 @@ extern "C" { int findoption(const char *s, const struct locale *lang); - param_t findparam(const char *s, const struct locale *lang); - param_t findparam_block(const char *s, const struct locale *lang, bool any_locale); - param_t findparam_ex(const char *s, const struct locale * lang); - bool isparam(const char *s, const struct locale * lang, param_t param); - param_t getparam(const struct locale *lang); - const char * game_name(void); const char * game_mailcmd(void); int game_id(void); @@ -109,7 +103,6 @@ extern "C" { /* globale settings des Spieles */ typedef struct settings { - struct attrib *attribs; void *vm_state; } settings; @@ -133,12 +126,9 @@ extern "C" { struct order *default_order(const struct locale *lang); - void init_parameters(struct locale *lang); - void free_gamedata(void); void free_config(void); - extern const char *parameters[]; extern settings global; #ifdef __cplusplus diff --git a/src/kernel/config.test.c b/src/kernel/config.test.c index e99ba9d08..cc476c6c3 100644 --- a/src/kernel/config.test.c +++ b/src/kernel/config.test.c @@ -5,9 +5,12 @@ #include #include #include -#include + #include -#include +#include +#include + +#include #include @@ -19,7 +22,6 @@ struct critbit_tree; static void test_read_unitid(CuTest *tc) { unit *u; order *ord; - attrib *a; struct locale *lang; struct terrain_type *t_plain; @@ -28,8 +30,7 @@ static void test_read_unitid(CuTest *tc) { /* note that the english order is FIGHT, not COMBAT, so this is a poor example */ t_plain = test_create_terrain("plain", LAND_REGION); u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, t_plain)); - a = a_add(&u->attribs, a_new(&at_alias)); - a->data.i = atoi36("42"); /* this unit is also TEMP 42 */ + usetalias(u, atoi36("42")); ord = create_order(K_GIVE, lang, "TEMP 42"); init_order_depr(ord); @@ -63,7 +64,6 @@ static void test_read_unitid(CuTest *tc) { static void test_getunit(CuTest *tc) { unit *u, *u2; order *ord; - attrib *a; struct region *r; struct locale *lang; struct terrain_type *t_plain; @@ -73,8 +73,9 @@ static void test_getunit(CuTest *tc) { /* note that the english order is FIGHT, not COMBAT, so this is a poor example */ t_plain = test_create_terrain("plain", LAND_REGION); u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, t_plain)); - a = a_add(&u->attribs, a_new(&at_alias)); - a->data.i = atoi36("42"); /* this unit is also TEMP 42 */ + /* This unit is also TEMP 42: */ + usetalias(u, atoi36("42")); + r = test_create_region(1, 0, t_plain); ord = create_order(K_GIVE, lang, itoa36(u->no)); diff --git a/src/kernel/connection.c b/src/kernel/connection.c index 213700fe1..995c276bb 100644 --- a/src/kernel/connection.c +++ b/src/kernel/connection.c @@ -26,9 +26,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "terrain.h" #include "unit.h" -#include +#include #include -#include +#include #include #include #include @@ -263,7 +263,7 @@ bool b_blocknone(const connection * b, const unit * u, const region * r) bool b_rvisible(const connection * b, const region * r) { - return (bool)(b->to == r || b->from == r); + return (b->to == r || b->from == r); } bool b_fvisible(const connection * b, const struct faction * f, @@ -412,7 +412,7 @@ b_blockfogwall(const connection * b, const unit * u, const region * r) UNUSED_ARG(b); if (!u) return true; - return (bool)(effskill(u, SK_PERCEPTION, r) > 4); /* Das ist die alte Nebelwand */ + return (effskill(u, SK_PERCEPTION, r) > 4); /* Das ist die alte Nebelwand */ } /** Legacy type used in old Eressea games, no longer in use. */ @@ -440,7 +440,7 @@ static const char *b_nameillusionwall(const connection * b, const region * r, return (f && fno == f->no) ? "illusionwall" : "wall"; if (gflags & GF_ARTICLE) { return LOC(f->locale, mkname("border", (f - && fno == f->subscription) ? "an_illusionwall" : "a_wall")); + && fno == f->uid) ? "an_illusionwall" : "a_wall")); } return LOC(f->locale, mkname("border", (f && fno == f->no) ? "illusionwall" : "wall")); diff --git a/src/kernel/curse.c b/src/kernel/curse.c index f6be51dac..bf3c8fef0 100644 --- a/src/kernel/curse.c +++ b/src/kernel/curse.c @@ -34,9 +34,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "unit.h" /* util includes */ -#include +#include #include -#include +#include #include #include #include @@ -229,7 +229,7 @@ int curse_read(variant *var, void *owner, gamedata *data) READ_INT(store, &c->data.i); } if (c->type->typ == CURSETYP_REGION) { - int rr = read_region_reference(data, (region **)&c->data.v, NULL); + int rr = read_region_reference(data, (region **)&c->data.v); if (ur == 0 && rr == 0 && !c->data.v) { return AT_READ_FAIL; } diff --git a/src/kernel/curse.test.c b/src/kernel/curse.test.c index dc3603d50..886e25ee4 100644 --- a/src/kernel/curse.test.c +++ b/src/kernel/curse.test.c @@ -4,9 +4,9 @@ #include #include #include -#include +#include #include -#include +#include #include #include #include diff --git a/src/kernel/database.c b/src/kernel/database.c index eaf695613..796aa2380 100644 --- a/src/kernel/database.c +++ b/src/kernel/database.c @@ -1,38 +1,29 @@ -#include +#include "config.h" #include "database.h" - -#include - -#include -#include -#include - -#include - #include "db/driver.h" -order_data *dblib_load_order(int id) +void swapdb_open(void) { - if (id > 0) { - return db_driver_order_load(id); - } - return NULL; + const char *dbname; + dbname = config_get("game.dbswap"); + db_driver_open(DB_SWAP, dbname); } -int dblib_save_order(order_data *od) +void swapdb_close(void) { - if (od->_str) { - return db_driver_order_save(od); - } + db_driver_close(DB_SWAP); +} + +dbrow_id db_string_save(const char *s) { + (void)s; return 0; } -void dblib_open(void) -{ - db_driver_open(); +dbrow_id dbstring_save(const char *s) { + return db_driver_string_save(s); } -void dblib_close(void) -{ - db_driver_close(); +const char *dbstring_load(dbrow_id id, size_t *size) { + return db_driver_string_load(id, size); } + diff --git a/src/kernel/database.h b/src/kernel/database.h index 0dd5a70fb..8147ccc61 100644 --- a/src/kernel/database.h +++ b/src/kernel/database.h @@ -1,21 +1,11 @@ -#ifndef H_DATABASE -#define H_DATABASE +#pragma once + +#include "db/driver.h" #include -#ifdef __cplusplus -extern "C" { -#endif +void swapdb_open(void); +void swapdb_close(void); - struct order_data; - - void dblib_open(void); - void dblib_close(void); - - struct order_data *dblib_load_order(int id); - int dblib_save_order(struct order_data *od); - -#ifdef __cplusplus -} -#endif -#endif +dbrow_id dbstring_save(const char *s); +const char *dbstring_load(dbrow_id id, size_t *size); diff --git a/src/kernel/database.test.c b/src/kernel/database.test.c index 2e1104185..c5aae1af6 100644 --- a/src/kernel/database.test.c +++ b/src/kernel/database.test.c @@ -1,14 +1,28 @@ #include #include +#include +#include #include "database.h" -#include "orderdb.h" +#include "db/driver.h" #include #include +#include #include +static void test_orderdb(CuTest *tc) { + order_data *od = NULL; + const char * s = "GIB enno 1 Hodor"; + + odata_create(&od, strlen(s) + 1, s); + CuAssertPtrNotNull(tc, od); + CuAssertStrEquals(tc, s, od->_str); + CuAssertTrue(tc, od->_refcount >= 1); + odata_release(od); +} + static void test_save_load_order(CuTest *tc) { order_data *od; int id; @@ -31,10 +45,31 @@ static void test_save_load_order(CuTest *tc) { test_teardown(); } +static void test_update_faction(CuTest *tc) { + faction *f; + int uid; + + test_setup(); + db_driver_open(DB_GAME, NULL); + f = test_create_faction(NULL); + uid = db_driver_faction_save(f->uid, f->no, 0, + faction_getemail(f), + faction_getpassword(f)); + f->uid = uid; + uid = db_driver_faction_save(f->uid, f->no, 0, + faction_getemail(f), + faction_getpassword(f)); + CuAssertIntEquals(tc, f->uid, uid); + db_driver_close(DB_GAME); + test_teardown(); +} + CuSuite *get_db_suite(void) { CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_save_load_order); + SUITE_ADD_TEST(suite, test_update_faction); + SUITE_ADD_TEST(suite, test_orderdb); return suite; } diff --git a/src/kernel/db/berkeley.c b/src/kernel/db/berkeley.c index 210c36f01..9a10e4bf8 100644 --- a/src/kernel/db/berkeley.c +++ b/src/kernel/db/berkeley.c @@ -4,36 +4,35 @@ #include #include "driver.h" -#include -#include - #include #include static DB *g_dbp; -void db_driver_open(void) +void db_driver_open(database_t db, const char *dbname) { - int ret; - u_int32_t flags = DB_CREATE; - const char * dbname; + if (db == DB_SWAP) { + int ret; + u_int32_t flags = DB_CREATE; - dbname = config_get("game.dbname"); - ret = db_create(&g_dbp, NULL, 0); - assert(ret==0); + ret = db_create(&g_dbp, NULL, 0); + assert(ret == 0); - ret = g_dbp->open(g_dbp, NULL, dbname, NULL, DB_RECNO, flags, 0); - assert(ret==0); + ret = g_dbp->open(g_dbp, NULL, dbname, NULL, DB_RECNO, flags, 0); + assert(ret == 0); + } } -void db_driver_close(void) +void db_driver_close(database_t db) { - int ret; - ret = g_dbp->close(g_dbp, 0); - assert(ret==0); + if (db == DB_SWAP) { + int ret; + ret = g_dbp->close(g_dbp, 0); + assert(ret == 0); + } } -int db_driver_order_save(struct order_data *od) +int db_driver_order_save(const char *str) { int ret; DBT key, data; @@ -46,7 +45,7 @@ int db_driver_order_save(struct order_data *od) key.size = key.ulen = sizeof(recno); key.flags = DB_DBT_USERMEM; data.data = (void *)od->_str; - data.size = data.ulen = strlen(od->_str) + 1; + data.size = data.ulen = strlen(str) + 1; data.flags = DB_DBT_USERMEM; ret = g_dbp->put(g_dbp, NULL, &key, &data, DB_APPEND); assert(ret == 0); @@ -74,3 +73,8 @@ struct order_data *db_driver_order_load(int id) return od; } +int db_driver_faction_save(int id, int no, int turn, const char *email, const char *password) +{ + return -1; +} + diff --git a/src/kernel/db/critbit.c b/src/kernel/db/critbit.c deleted file mode 100644 index 9afb0926d..000000000 --- a/src/kernel/db/critbit.c +++ /dev/null @@ -1,67 +0,0 @@ -#include -#include "driver.h" - -#include -#include - -#include - -#include -#include -#include - -static critbit_tree cb_orders = { 0 }; -static int auto_id = -1; - -struct cb_entry { - int id; - order_data *data; -}; - -order_data *db_driver_order_load(int id) -{ - void * match; - - assert(id>0); - if (cb_find_prefix(&cb_orders, &id, sizeof(id), &match, 1, 0) > 0) { - struct cb_entry *ent = (struct cb_entry *)match; - order_data * od = ent->data; - ++od->_refcount; - return od; - } - return NULL; -} - -int db_driver_order_save(order_data *od) -{ - struct cb_entry ent; - - assert(od && od->_str); - ++od->_refcount; - ent.id = ++auto_id; - ent.data = od; - cb_insert(&cb_orders, &ent, sizeof(ent)); - return ent.id; -} - -static int free_data_cb(const void *match, const void *key, size_t keylen, - void *udata) -{ - struct cb_entry * ent = (struct cb_entry *)match; - order_data *od = ent->data; - odata_release(od); - return 0; -} - -void db_driver_open(void) -{ - assert(auto_id == -1); - auto_id = 0; -} - -void db_driver_close(void) -{ - cb_foreach(&cb_orders, NULL, 0, free_data_cb, NULL); - cb_clear(&cb_orders); - auto_id = -1; -} diff --git a/src/kernel/db/driver.h b/src/kernel/db/driver.h index df839b93d..341653991 100644 --- a/src/kernel/db/driver.h +++ b/src/kernel/db/driver.h @@ -1,8 +1,22 @@ #pragma once +#include + struct order_data; -void db_driver_open(void); -void db_driver_close(void); -int db_driver_order_save(struct order_data *od); -struct order_data *db_driver_order_load(int id); +typedef unsigned int dbrow_id; + +extern void odata_create(struct order_data **pdata, size_t len, const char *str); + +typedef enum database_t { + DB_SWAP, + DB_GAME, +} database_t; + +int db_driver_open(database_t db, const char *dbname); +void db_driver_close(database_t db); +dbrow_id db_driver_order_save(const char *str); +struct order_data *db_driver_order_load(dbrow_id id); +dbrow_id db_driver_faction_save(dbrow_id id, int no, int turn, const char *email, const char *password); +dbrow_id db_driver_string_save(const char *s); +const char *db_driver_string_load(dbrow_id id, size_t *size); diff --git a/src/kernel/db/memory.c b/src/kernel/db/memory.c new file mode 100644 index 000000000..0f572a99e --- /dev/null +++ b/src/kernel/db/memory.c @@ -0,0 +1,70 @@ +#ifdef _MSC_VER +#include +#endif +#include "driver.h" + +#include +#include + +#include + +#include +#include +#include + +static selist * g_orders; +static int auto_id = -1; + +struct order_data *db_driver_order_load(int id) +{ + void * match; + + assert(id>0); + match = selist_get(g_orders, id - 1); + if (match) { + char * str = (char *)match; + struct order_data * od = NULL; + odata_create(&od, strlen(str), str); + return od; + } + return NULL; +} + +int db_driver_order_save(const char * str) +{ + assert(str); + selist_push(&g_orders, str_strdup(str)); + return ++auto_id; +} + +int db_driver_faction_save(int id, int no, int turn, const char *email, const char *password) +{ + return -1; +} + +static void free_data_cb(void *match) +{ + char *str = (char *)match; + free(str); +} + +int db_driver_open(database_t db, const char *dbname) +{ + (void)dbname; + if (db == DB_SWAP) { + assert(auto_id == -1); + auto_id = 0; + return 0; + } + return -1; +} + +void db_driver_close(database_t db) +{ + if (db == DB_SWAP) { + selist_foreach(g_orders, free_data_cb); + selist_free(g_orders); + g_orders = NULL; + auto_id = -1; + } +} diff --git a/src/kernel/db/sqlite.c b/src/kernel/db/sqlite.c index b3090cca0..29638d900 100644 --- a/src/kernel/db/sqlite.c +++ b/src/kernel/db/sqlite.c @@ -1,8 +1,6 @@ #include #include -#include -#include #include @@ -11,123 +9,297 @@ #include #include +#include #include #include +#include #include -static sqlite3 *g_db; -static sqlite3_stmt * g_stmt_insert; -static sqlite3_stmt * g_stmt_select; +static sqlite3 *g_game_db; +static sqlite3 *g_swap_db; +static sqlite3_stmt * g_stmt_insert_string; +static sqlite3_stmt * g_stmt_select_string; +static sqlite3_stmt * g_stmt_insert_order; +static sqlite3_stmt * g_stmt_select_order; +static sqlite3_stmt * g_stmt_update_faction; +static sqlite3_stmt * g_stmt_insert_faction; -static int g_order_batchsize; -static int g_order_tx_size; +static int g_insert_batchsize; +static int g_insert_tx_size; -order_data *db_driver_order_load(int id) +static void end_transaction(void) { + if (g_insert_tx_size > 0) { + int err; + g_insert_tx_size = 0; + err = sqlite3_exec(g_swap_db, "COMMIT", NULL, NULL, NULL); + assert(err == SQLITE_OK); + } +} + +struct order_data *db_driver_order_load(dbrow_id id) { - order_data * od = NULL; + struct order_data * od = NULL; int err; ERRNO_CHECK(); - if (g_order_tx_size > 0) { - g_order_tx_size = 0; - err = sqlite3_exec(g_db, "COMMIT", NULL, NULL, NULL); - assert(err == SQLITE_OK); + end_transaction(); + err = sqlite3_reset(g_stmt_select_order); + assert(err == SQLITE_OK); + err = sqlite3_bind_int(g_stmt_select_order, 1, id); + assert(err == SQLITE_OK); + err = sqlite3_step(g_stmt_select_order); + if (err == SQLITE_ROW) { + const unsigned char *text; + int bytes; + text = sqlite3_column_text(g_stmt_select_order, 0); + bytes = sqlite3_column_bytes(g_stmt_select_order, 0); + assert(bytes > 0); + odata_create(&od, 1+(size_t)bytes, (const char *)text); + ERRNO_CHECK(); + return od; } - err = sqlite3_reset(g_stmt_select); - assert(err == SQLITE_OK); - err = sqlite3_bind_int(g_stmt_select, 1, id); - assert(err == SQLITE_OK); - do { - err = sqlite3_step(g_stmt_select); - if (err == SQLITE_ROW) { - const unsigned char *text; - int bytes; - bytes = sqlite3_column_bytes(g_stmt_select, 0); - assert(bytes > 0); - text = sqlite3_column_text(g_stmt_select, 0); - odata_create(&od, 1+(size_t)bytes, (const char *)text); - ERRNO_CHECK(); - return od; - } - } while (err == SQLITE_ROW); - assert(err == SQLITE_DONE); ERRNO_CHECK(); return NULL; } -int db_driver_order_save(order_data *od) -{ +dbrow_id db_driver_order_save(const char *str) { int err; sqlite3_int64 id; - assert(od && od->_str); + assert(str); ERRNO_CHECK(); - if (g_order_batchsize > 0) { - if (g_order_tx_size == 0) { - err = sqlite3_exec(g_db, "BEGIN TRANSACTION", NULL, NULL, NULL); + if (g_insert_batchsize > 0) { + if (g_insert_tx_size == 0) { + err = sqlite3_exec(g_swap_db, "BEGIN TRANSACTION", NULL, NULL, NULL); assert(err == SQLITE_OK); } } - err = sqlite3_reset(g_stmt_insert); + err = sqlite3_reset(g_stmt_insert_order); assert(err == SQLITE_OK); - err = sqlite3_bind_text(g_stmt_insert, 1, od->_str, -1, SQLITE_STATIC); + err = sqlite3_bind_text(g_stmt_insert_order, 1, str, -1, SQLITE_STATIC); assert(err == SQLITE_OK); - err = sqlite3_step(g_stmt_insert); + err = sqlite3_step(g_stmt_insert_order); assert(err == SQLITE_DONE); - id = sqlite3_last_insert_rowid(g_db); - assert(id <= INT_MAX); + id = sqlite3_last_insert_rowid(g_swap_db); + assert(id > 0 && id <= UINT_MAX); - if (g_order_batchsize > 0) { - if (++g_order_tx_size >= g_order_batchsize) { - err = sqlite3_exec(g_db, "COMMIT", NULL, NULL, NULL); - assert(err == SQLITE_OK); - g_order_tx_size = 0; + if (g_insert_batchsize > 0) { + if (++g_insert_tx_size >= g_insert_batchsize) { + end_transaction(); } } ERRNO_CHECK(); - return (int)id; + return (dbrow_id)id; } -void db_driver_open(void) -{ - int err; - const char *dbname; - ERRNO_CHECK(); - g_order_batchsize = config_get_int("game.dbbatch", 100); - dbname = config_get("game.dbname"); - if (!dbname) { - dbname = ""; +dbrow_id db_driver_faction_save(dbrow_id id, int no, int turn, const char *email, const char *password) +{ + sqlite3_int64 row_id; + int err; + + assert(g_game_db); + if (id != 0) { + int rows; + + err = sqlite3_reset(g_stmt_update_faction); + assert(err == SQLITE_OK); + err = sqlite3_bind_int(g_stmt_update_faction, 1, no); + assert(err == SQLITE_OK); + err = sqlite3_bind_int(g_stmt_update_faction, 2, turn); + assert(err == SQLITE_OK); + err = sqlite3_bind_text(g_stmt_update_faction, 3, email, -1, SQLITE_STATIC); + assert(err == SQLITE_OK); + err = sqlite3_bind_text(g_stmt_update_faction, 4, password, -1, SQLITE_STATIC); + assert(err == SQLITE_OK); + err = sqlite3_bind_int(g_stmt_update_faction, 5, id); + assert(err == SQLITE_OK); + err = sqlite3_step(g_stmt_update_faction); + assert(err == SQLITE_DONE); + rows = sqlite3_changes(g_game_db); + if (rows != 0) { + return id; + } } - err = sqlite3_open(dbname, &g_db); + err = sqlite3_reset(g_stmt_insert_faction); assert(err == SQLITE_OK); - err = sqlite3_exec(g_db, "PRAGMA journal_mode=OFF", NULL, NULL, NULL); + err = sqlite3_bind_int(g_stmt_insert_faction, 1, no); assert(err == SQLITE_OK); - err = sqlite3_exec(g_db, "PRAGMA synchronous=OFF", NULL, NULL, NULL); + err = sqlite3_bind_int(g_stmt_insert_faction, 2, turn); assert(err == SQLITE_OK); - err = sqlite3_exec(g_db, "CREATE TABLE IF NOT EXISTS orders (id INTEGER PRIMARY KEY, data TEXT NOT NULL)", NULL, NULL, NULL); + err = sqlite3_bind_text(g_stmt_insert_faction, 3, email, -1, SQLITE_STATIC); assert(err == SQLITE_OK); - err = sqlite3_prepare_v2(g_db, "INSERT INTO orders (data) VALUES (?)", -1, &g_stmt_insert, NULL); - assert(err == SQLITE_OK); - err = sqlite3_prepare_v2(g_db, "SELECT data FROM orders WHERE id = ?", -1, &g_stmt_select, NULL); + err = sqlite3_bind_text(g_stmt_insert_faction, 4, password, -1, SQLITE_STATIC); assert(err == SQLITE_OK); + err = sqlite3_step(g_stmt_insert_faction); + assert(err == SQLITE_DONE); ERRNO_CHECK(); + + row_id = sqlite3_last_insert_rowid(g_game_db); + assert(row_id>0 && row_id <= UINT_MAX); + return (dbrow_id)row_id; } -void db_driver_close(void) +static int db_open_game(const char *dbname) { + int err; + + err = sqlite3_open(dbname, &g_game_db); + assert(err == SQLITE_OK); + err = sqlite3_exec(g_game_db, "CREATE TABLE IF NOT EXISTS factions (id INTEGER PRIMARY KEY, no INTEGER NOT NULL, email VARCHAR(128), password VARCHAR(128), turn INTEGER NOT NULL)", NULL, NULL, NULL); + assert(err == SQLITE_OK); + err = sqlite3_prepare_v2(g_game_db, "UPDATE factions SET no=?, turn=?, email=?, password=? WHERE id=?", -1, &g_stmt_update_faction, NULL); + assert(err == SQLITE_OK); + err = sqlite3_prepare_v2(g_game_db, "INSERT INTO factions (no, turn, email, password) VALUES (?,?,?,?)", -1, &g_stmt_insert_faction, NULL); + assert(err == SQLITE_OK); + + ERRNO_CHECK(); + return 0; +} + +static int db_open_swap(const char *dbname) { + int err; + + g_insert_batchsize = config_get_int("game.dbbatch", 100); + + err = sqlite3_open(dbname, &g_swap_db); + assert(err == SQLITE_OK); + err = sqlite3_exec(g_swap_db, "PRAGMA journal_mode=OFF", NULL, NULL, NULL); + assert(err == SQLITE_OK); + err = sqlite3_exec(g_swap_db, "PRAGMA synchronous=OFF", NULL, NULL, NULL); + assert(err == SQLITE_OK); + err = sqlite3_exec(g_swap_db, "CREATE TABLE IF NOT EXISTS orders (id INTEGER PRIMARY KEY, data TEXT NOT NULL)", NULL, NULL, NULL); + assert(err == SQLITE_OK); + err = sqlite3_exec(g_swap_db, "CREATE TABLE IF NOT EXISTS strings (id INTEGER PRIMARY KEY, data TEXT NOT NULL)", NULL, NULL, NULL); + assert(err == SQLITE_OK); + err = sqlite3_prepare_v2(g_swap_db, "INSERT INTO strings (data) VALUES (?)", -1, &g_stmt_insert_string, NULL); + assert(err == SQLITE_OK); + err = sqlite3_prepare_v2(g_swap_db, "SELECT data FROM strings WHERE id=?", -1, &g_stmt_select_string, NULL); + assert(err == SQLITE_OK); + err = sqlite3_prepare_v2(g_swap_db, "INSERT INTO orders (data) VALUES (?)", -1, &g_stmt_insert_order, NULL); + assert(err == SQLITE_OK); + err = sqlite3_prepare_v2(g_swap_db, "SELECT data FROM orders WHERE id=?", -1, &g_stmt_select_order, NULL); + assert(err == SQLITE_OK); + ERRNO_CHECK(); + return 0; +} + +static const char *g_swapname; + +int db_driver_open(database_t db, const char *dbname) +{ + ERRNO_CHECK(); + + if (!dbname) { + /* by default, use an in-memory database */ + dbname = ":memory:"; + } + if (db == DB_SWAP) { + g_swapname = dbname; + return db_open_swap(dbname); + } + else if (db == DB_GAME) { + return db_open_game(dbname); + } + return -1; +} + +void db_driver_close(database_t db) { int err; ERRNO_CHECK(); - err = sqlite3_finalize(g_stmt_select); - assert(err == SQLITE_OK); - err = sqlite3_finalize(g_stmt_insert); - assert(err == SQLITE_OK); - err = sqlite3_close(g_db); - assert(err == SQLITE_OK); + if (db == DB_SWAP) { + assert(g_swap_db); + err = sqlite3_finalize(g_stmt_select_string); + assert(err == SQLITE_OK); + err = sqlite3_finalize(g_stmt_insert_string); + assert(err == SQLITE_OK); + err = sqlite3_finalize(g_stmt_select_order); + assert(err == SQLITE_OK); + err = sqlite3_finalize(g_stmt_insert_order); + assert(err == SQLITE_OK); + err = sqlite3_close(g_swap_db); + assert(err == SQLITE_OK); + if (g_swapname) { + FILE * F = fopen(g_swapname, "r"); + if (F) { + fclose(F); + if (0 != remove(g_swapname)) { + log_error("could not remove %s: %s", g_swapname, + strerror(errno)); + errno = 0; + } + } + } + } + else if (db == DB_GAME) { + assert(g_game_db); + err = sqlite3_finalize(g_stmt_update_faction); + assert(err == SQLITE_OK); + err = sqlite3_finalize(g_stmt_insert_faction); + assert(err == SQLITE_OK); + err = sqlite3_close(g_game_db); + assert(err == SQLITE_OK); + } ERRNO_CHECK(); } +dbrow_id db_driver_string_save(const char *str) { + int err; + sqlite3_int64 id; + + assert(str); + + ERRNO_CHECK(); + + if (g_insert_batchsize > 0) { + if (g_insert_tx_size == 0) { + err = sqlite3_exec(g_swap_db, "BEGIN TRANSACTION", NULL, NULL, NULL); + assert(err == SQLITE_OK); + } + } + + err = sqlite3_reset(g_stmt_insert_string); + assert(err == SQLITE_OK); + err = sqlite3_bind_text(g_stmt_insert_string, 1, str, -1, SQLITE_STATIC); + assert(err == SQLITE_OK); + err = sqlite3_step(g_stmt_insert_string); + assert(err == SQLITE_DONE); + id = sqlite3_last_insert_rowid(g_swap_db); + assert(id > 0 && id <= UINT_MAX); + + if (g_insert_batchsize > 0) { + if (++g_insert_tx_size >= g_insert_batchsize) { + end_transaction(); + } + } + ERRNO_CHECK(); + return (dbrow_id)id; +} + +const char *db_driver_string_load(dbrow_id id, size_t *size) { + int err; + + end_transaction(); + err = sqlite3_reset(g_stmt_select_string); + assert(err == SQLITE_OK); + err = sqlite3_bind_int(g_stmt_select_string, 1, id); + assert(err == SQLITE_OK); + err = sqlite3_step(g_stmt_select_string); + if (err == SQLITE_ROW) { + const unsigned char *text; + text = sqlite3_column_text(g_stmt_select_string, 0); + if (size) { + int bytes = sqlite3_column_bytes(g_stmt_select_string, 0); + assert(bytes > 0); + *size = (size_t)bytes; + } + ERRNO_CHECK(); + return (const char *)text; + } + ERRNO_CHECK(); + return NULL; +} diff --git a/src/util/event.c b/src/kernel/event.c similarity index 98% rename from src/util/event.c rename to src/kernel/event.c index d6aa6f338..f1ff825f5 100644 --- a/src/util/event.c +++ b/src/kernel/event.c @@ -18,12 +18,12 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include "event.h" +#include "attrib.h" /* util includes */ -#include "attrib.h" -#include "gamedata.h" -#include "log.h" -#include "strings.h" +#include +#include +#include #include diff --git a/src/util/event.h b/src/kernel/event.h similarity index 99% rename from src/util/event.h rename to src/kernel/event.h index ad4ca373d..c6c880c4c 100644 --- a/src/util/event.h +++ b/src/kernel/event.h @@ -22,7 +22,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -#include "variant.h" +#include struct attrib; struct trigger; diff --git a/src/kernel/faction.c b/src/kernel/faction.c index b4dfe51ca..c0c908186 100755 --- a/src/kernel/faction.c +++ b/src/kernel/faction.c @@ -22,6 +22,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "calendar.h" #include "config.h" +#include "database.h" #include "alliance.h" #include "ally.h" #include "curse.h" @@ -42,10 +43,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include /* util includes */ -#include +#include #include -#include -#include +#include +#include #include #include #include @@ -53,7 +54,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include -#include #include #include #include @@ -105,8 +105,6 @@ static void free_faction(faction * f) freelist(f->allies); free(f->email); - free(f->banner); - free(f->_password); free(f->name); if (f->seen_factions) { selist_free(f->seen_factions); @@ -119,7 +117,7 @@ static void free_faction(faction * f) i_freeall(&f->items); - freelist(f->ursprung); + freelist(f->origin); } #define FMAXHASH 2039 @@ -230,7 +228,7 @@ static int unused_faction_id(void) } faction *addfaction(const char *email, const char *password, - const struct race * frace, const struct locale * loc, int subscription) + const struct race * frace, const struct locale * loc) { faction *f = calloc(sizeof(faction), 1); char buf[128]; @@ -245,16 +243,18 @@ faction *addfaction(const char *email, const char *password, f->alliance_joindate = turn; f->lastorders = turn; f->_alive = true; + f->password_id = 0; f->age = 0; f->race = frace; f->magiegebiet = 0; f->locale = loc; - f->subscription = subscription; + f->uid = 0; f->flags = FFL_ISNEW|FFL_PWMSG; - if (!password) password = itoa36(rng_int()); - faction_setpassword(f, password_encode(password, PASSWORD_DEFAULT)); - ADDMSG(&f->msgs, msg_message("changepasswd", "value", password)); + if (password) { + faction_setpassword(f, password_hash(password, PASSWORD_DEFAULT)); + ADDMSG(&f->msgs, msg_message("changepasswd", "value", password)); + } f->options = WANT_OPTION(O_REPORT) | WANT_OPTION(O_ZUGVORLAGE) | @@ -319,29 +319,25 @@ unit *addplayer(region * r, faction * f) bool checkpasswd(const faction * f, const char *passwd) { + const char *pwhash; if (!passwd) return false; - if (f->_password && password_verify(f->_password, passwd) == VERIFY_FAIL) { + pwhash = faction_getpassword(f); + if (pwhash && password_verify(pwhash, passwd) == VERIFY_FAIL) { log_info("password check failed: %s", factionname(f)); return false; } return true; } -void resolve_faction(faction *f) -{ - resolve(RESOLVE_FACTION | f->no, f); -} - -int read_faction_reference(gamedata * data, faction **fp, resolve_fun fun) +int read_faction_reference(gamedata * data, faction **fp) { int id; READ_INT(data->store, &id); if (id > 0) { *fp = findfaction(id); if (*fp == NULL) { - *fp = NULL; - ur_add(RESOLVE_FACTION | id, (void **)fp, fun); + *fp = faction_create(id); } } else { @@ -393,7 +389,7 @@ faction *get_or_create_monsters(void) if (!f) { const race *rc = rc_get_or_create("dragon"); const char *email = config_get("monster.email"); - f = addfaction(email, NULL, rc, default_locale, 0); + f = addfaction(email, NULL, rc, default_locale); renumber_faction(f, MONSTER_ID); faction_setname(f, "Monster"); fset(f, FFL_NPC | FFL_NOIDLEOUT); @@ -493,7 +489,7 @@ void destroyfaction(faction ** fp) handle_event(f->attribs, "destroy", f); if (f->alliance) { - setalliance(f, 0); + setalliance(f, NULL); } funhash(f); @@ -515,35 +511,6 @@ void destroyfaction(faction ** fp) } } -int get_alliance(const faction * a, const faction * b) -{ - const ally *sf = a->allies; - for (; sf != NULL; sf = sf->next) { - if (sf->faction == b) { - return sf->status; - } - } - return 0; -} - -void set_alliance(faction * a, faction * b, int status) -{ - ally **sfp; - sfp = &a->allies; - while (*sfp) { - ally *sf = *sfp; - if (sf->faction == b) - break; - sfp = &sf->next; - } - if (*sfp == NULL) { - ally *sf = ally_add(sfp, b); - sf->status = status; - return; - } - (*sfp)->status |= status; -} - void renumber_faction(faction * f, int no) { funhash(f); @@ -589,23 +556,30 @@ void faction_setemail(faction * self, const char *email) self->email = NULL; } -const char *faction_getbanner(const faction * self) +const char *faction_getbanner(const faction * f) { - return self->banner ? self->banner : ""; + if (f->banner_id > 0) { + return dbstring_load(f->banner_id, NULL); + } + return NULL; } -void faction_setbanner(faction * self, const char *banner) +void faction_setbanner(faction * f, const char *banner) { - free(self->banner); - if (banner) - self->banner = str_strdup(banner); + f->banner_id = dbstring_save(banner); +} + +const char *faction_getpassword(const faction *f) { + if (f->password_id > 0) { + return dbstring_load(f->password_id, NULL); + } + return NULL; } void faction_setpassword(faction * f, const char *pwhash) { assert(pwhash); - free(f->_password); - f->_password = str_strdup(pwhash); + f->password_id = dbstring_save(pwhash); } bool valid_race(const struct faction *f, const struct race *rc) @@ -633,7 +607,7 @@ struct spellbook * faction_get_spellbook(struct faction *f) if (f->magiegebiet != M_GRAY) { return get_spellbook(magic_school[f->magiegebiet]); } - return 0; + return NULL; } static int allied_skillcount(const faction * f, skill_t sk) @@ -725,10 +699,10 @@ bool faction_alive(const faction *f) { void faction_getorigin(const faction * f, int id, int *x, int *y) { - ursprung *ur; + origin *ur; assert(f && x && y); - for (ur = f->ursprung; ur; ur = ur->next) { + for (ur = f->origin; ur; ur = ur->next) { if (ur->id == id) { *x = ur->x; *y = ur->y; @@ -737,24 +711,27 @@ void faction_getorigin(const faction * f, int id, int *x, int *y) } } -void faction_setorigin(faction * f, int id, int x, int y) -{ - ursprung *ur; - assert(f != NULL); - for (ur = f->ursprung; ur; ur = ur->next) { - if (ur->id == id) { - ur->x = ur->x + x; - ur->y = ur->y + y; - return; - } - } - - ur = calloc(1, sizeof(ursprung)); +static origin *new_origin(int id, int x, int y) { + origin *ur = (origin *)calloc(1, sizeof(origin)); ur->id = id; ur->x = x; ur->y = y; + return ur; +} - addlist(&f->ursprung, ur); +void faction_setorigin(faction * f, int id, int x, int y) +{ + origin **urp; + assert(f != NULL); + for (urp = &f->origin; *urp; urp = &(*urp)->next) { + origin *ur = *urp; + if (ur->id == id) { + ur->x += x; + ur->y += y; + return; + } + } + *urp = new_origin(id, x, y); } @@ -839,7 +816,8 @@ int writepasswd(void) for (f = factions; f; f = f->next) { fprintf(F, "%s:%s:%s:%d\n", - itoa36(f->no), faction_getemail(f), f->_password, f->subscription); + itoa36(f->no), faction_getemail(f), + faction_getpassword(f), f->uid); } fclose(F); return 0; @@ -872,3 +850,11 @@ void free_factions(void) { free_flist(&factions); free_flist(&dead_factions); } + +faction *faction_create(int no) +{ + faction *f = (faction *)calloc(1, sizeof(faction)); + f->no = no; + fhash(f); + return f; +} diff --git a/src/kernel/faction.h b/src/kernel/faction.h index 8d13f64d1..0c579603a 100644 --- a/src/kernel/faction.h +++ b/src/kernel/faction.h @@ -21,6 +21,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "skill.h" #include "types.h" +#include "db/driver.h" #include #include @@ -37,7 +38,7 @@ extern "C" { struct attrib_type; struct gamedata; struct selist; - + /* faction flags */ #define FFL_NOAID (1<<0) /* Hilfsflag Kampf */ #define FFL_ISNEW (1<<1) @@ -54,6 +55,12 @@ extern "C" { #define FFL_NPC (1<<25) /* eine Partei mit Monstern */ #define FFL_SAVEMASK (FFL_DEFENDER|FFL_NPC|FFL_NOIDLEOUT|FFL_CURSED) + typedef struct origin { + struct origin *next; + int id; + int x, y; + } origin; + typedef struct faction { struct faction *next; struct faction *nexthash; @@ -61,25 +68,25 @@ extern "C" { struct region *first; struct region *last; int no; - int subscription; + int uid; int flags; char *name; - char *banner; + dbrow_id banner_id; char *email; - char *_password; + dbrow_id password_id; int max_spelllevel; struct spellbook *spellbook; const struct locale *locale; int lastorders; int age; - struct ursprung *ursprung; + struct origin *origin; const struct race *race; magic_t magiegebiet; int newbies; int num_people; /* Anzahl Personen ohne Monster */ int num_units; int options; - struct ally *allies; /* alliedgroup and others should check sf.faction.alive before using a faction from f.allies */ + struct allies *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 */ score_t score; struct alliance *alliance; @@ -104,6 +111,8 @@ extern "C" { void fhash(struct faction *f); void funhash(struct faction *f); + int faction_ally_status(const faction *f, const faction *f2); + struct faction *findfaction(int n); int max_magicians(const faction * f); void set_show_item(faction * f, const struct item_type *itype); @@ -112,24 +121,19 @@ extern "C" { const char *factionname(const struct faction *f); struct unit *addplayer(struct region *r, faction * f); struct faction *addfaction(const char *email, const char *password, - const struct race *frace, const struct locale *loc, int subscription); + const struct race *frace, const struct locale *loc); bool checkpasswd(const faction * f, const char *passwd); int writepasswd(void); void destroyfaction(faction ** f); bool faction_alive(const struct faction *f); - - void set_alliance(struct faction *a, struct faction *b, int status); - int get_alliance(const struct faction *a, const struct faction *b); + struct faction *faction_create(int no); struct alliance *f_get_alliance(const struct faction *f); void write_faction_reference(const struct faction *f, struct storage *store); - int read_faction_reference(struct gamedata *data, struct faction **fp, resolve_fun fun); - -#define RESOLVE_FACTION (TYP_FACTION << 24) - void resolve_faction(struct faction *f); + int read_faction_reference(struct gamedata *data, struct faction **fp); void renumber_faction(faction * f, int no); void free_factions(void); @@ -148,6 +152,7 @@ extern "C" { void faction_setemail(struct faction *self, const char *email); void faction_setpassword(struct faction *self, const char *pwhash); + const char *faction_getpassword(const struct faction *f); bool valid_race(const struct faction *f, const struct race *rc); void faction_getorigin(const struct faction * f, int id, int *x, int *y); diff --git a/src/kernel/faction.test.c b/src/kernel/faction.test.c index 37ec70e50..66e3c3945 100644 --- a/src/kernel/faction.test.c +++ b/src/kernel/faction.test.c @@ -29,20 +29,18 @@ static void test_destroyfaction_allies(CuTest *tc) { faction *f1, *f2; region *r; - ally *al; test_setup(); r = test_create_region(0, 0, NULL); f1 = test_create_faction(NULL); test_create_unit(f1, r); f2 = test_create_faction(NULL); - al = ally_add(&f1->allies, f2); - al->status = HELP_FIGHT; - CuAssertIntEquals(tc, HELP_FIGHT, alliedgroup(0, f1, f2, f1->allies, HELP_ALL)); + ally_set(&f1->allies, f2, HELP_FIGHT); + CuAssertIntEquals(tc, HELP_FIGHT, alliedfaction(f1, f2, HELP_ALL)); CuAssertPtrEquals(tc, f2, f1->next); destroyfaction(&f1->next); CuAssertIntEquals(tc, false, faction_alive(f2)); - CuAssertIntEquals(tc, 0, alliedgroup(0, f1, f2, f1->allies, HELP_ALL)); + CuAssertIntEquals(tc, 0, alliedfaction(f1, f2, HELP_ALL)); test_teardown(); } @@ -57,7 +55,7 @@ static void test_remove_empty_factions_alliance(CuTest *tc) { CuAssertPtrEquals(tc, f, alliance_get_leader(al)); CuAssertIntEquals(tc, 1, selist_length(al->members)); remove_empty_factions(); - CuAssertPtrEquals(tc, 0, al->_leader); + CuAssertPtrEquals(tc, NULL, al->_leader); CuAssertIntEquals(tc, 0, selist_length(al->members)); test_teardown(); } @@ -75,7 +73,7 @@ static void test_remove_empty_factions(CuTest *tc) { CuAssertIntEquals(tc, false, f->_alive); CuAssertPtrEquals(tc, fm, factions); CuAssertPtrEquals(tc, NULL, fm->next); - CuAssertPtrEquals(tc, 0, findfaction(fno)); + CuAssertPtrEquals(tc, NULL, findfaction(fno)); CuAssertPtrEquals(tc, fm, get_monsters()); test_teardown(); } @@ -99,7 +97,7 @@ static void test_remove_dead_factions(CuTest *tc) { f->_alive = false; fno = f->no; remove_empty_factions(); - CuAssertPtrEquals(tc, 0, findfaction(fno)); + CuAssertPtrEquals(tc, NULL, findfaction(fno)); CuAssertPtrEquals(tc, fm, get_monsters()); test_teardown(); } @@ -112,19 +110,18 @@ static void test_addfaction(CuTest *tc) { test_setup(); rc = rc_get_or_create("human"); lang = test_create_locale(); - f = addfaction("test@eressea.de", "hurrdurr", rc, lang, 1234); + f = addfaction("test@eressea.de", NULL, rc, lang); CuAssertPtrNotNull(tc, f); CuAssertPtrNotNull(tc, f->name); CuAssertPtrEquals(tc, NULL, (void *)f->units); CuAssertPtrEquals(tc, NULL, (void *)f->next); - CuAssertPtrEquals(tc, NULL, (void *)f->banner); + CuAssertPtrEquals(tc, NULL, (void *)faction_getbanner(f)); CuAssertPtrEquals(tc, NULL, (void *)f->spellbook); - CuAssertPtrEquals(tc, NULL, (void *)f->ursprung); + CuAssertPtrEquals(tc, NULL, (void *)f->origin); CuAssertPtrEquals(tc, (void *)factions, (void *)f); CuAssertStrEquals(tc, "test@eressea.de", f->email); CuAssertTrue(tc, checkpasswd(f, "hurrdurr")); CuAssertPtrEquals(tc, (void *)lang, (void *)f->locale); - CuAssertIntEquals(tc, 1234, f->subscription); CuAssertIntEquals(tc, FFL_ISNEW|FFL_PWMSG, f->flags); CuAssertIntEquals(tc, 0, f->age); CuAssertTrue(tc, faction_alive(f)); @@ -138,7 +135,7 @@ static void test_check_passwd(CuTest *tc) { faction *f; f = test_create_faction(NULL); - faction_setpassword(f, password_encode("password", PASSWORD_DEFAULT)); + faction_setpassword(f, password_hash("password", PASSWORD_DEFAULT)); CuAssertTrue(tc, checkpasswd(f, "password")); CuAssertTrue(tc, !checkpasswd(f, "assword")); CuAssertTrue(tc, !checkpasswd(f, "PASSWORD")); @@ -163,11 +160,11 @@ static void test_set_origin(CuTest *tc) { test_setup(); pl = create_new_plane(0, "", 0, 19, 0, 19, 0); f = test_create_faction(NULL); - CuAssertPtrEquals(tc, 0, f->ursprung); + CuAssertPtrEquals(tc, NULL, f->origin); faction_setorigin(f, 0, 1, 1); - CuAssertIntEquals(tc, 0, f->ursprung->id); - CuAssertIntEquals(tc, 1, f->ursprung->x); - CuAssertIntEquals(tc, 1, f->ursprung->y); + CuAssertIntEquals(tc, 0, f->origin->id); + CuAssertIntEquals(tc, 1, f->origin->x); + CuAssertIntEquals(tc, 1, f->origin->y); faction_getorigin(f, 0, &x, &y); CuAssertIntEquals(tc, 1, x); CuAssertIntEquals(tc, 1, y); @@ -191,7 +188,7 @@ static void test_set_origin_bug(CuTest *tc) { faction_setorigin(f, 0, -10, 3); faction_setorigin(f, 0, -13, -4); adjust_coordinates(f, &x, &y, pl); - CuAssertIntEquals(tc, 0, f->ursprung->id); + CuAssertIntEquals(tc, 0, f->origin->id); CuAssertIntEquals(tc, -9, x); CuAssertIntEquals(tc, 2, y); test_teardown(); @@ -230,6 +227,18 @@ static void test_valid_race(CuTest *tc) { test_teardown(); } +static void test_dbstrings(CuTest *tc) { + const char *lipsum = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."; + faction *f; + test_setup(); + f = test_create_faction(NULL); + faction_setbanner(f, lipsum); + faction_setpassword(f, lipsum + 12); + CuAssertStrEquals(tc, lipsum, faction_getbanner(f)); + CuAssertStrEquals(tc, lipsum + 12, faction_getpassword(f)); + test_teardown(); +} + static void test_set_email(CuTest *tc) { faction *f; char email[10]; @@ -251,7 +260,7 @@ static void test_set_email(CuTest *tc) { faction_setemail(f, "bugs@eressea.de"); CuAssertStrEquals(tc, "bugs@eressea.de", f->email); faction_setemail(f, NULL); - CuAssertPtrEquals(tc, 0, f->email); + CuAssertPtrEquals(tc, NULL, f->email); CuAssertStrEquals(tc, "", faction_getemail(f)); test_teardown(); } @@ -336,6 +345,7 @@ CuSuite *get_faction_suite(void) SUITE_ADD_TEST(suite, test_check_passwd); SUITE_ADD_TEST(suite, test_valid_race); SUITE_ADD_TEST(suite, test_set_email); + SUITE_ADD_TEST(suite, test_dbstrings); SUITE_ADD_TEST(suite, test_save_special_items); return suite; } diff --git a/src/util/gamedata.c b/src/kernel/gamedata.c similarity index 98% rename from src/util/gamedata.c rename to src/kernel/gamedata.c index cd3fa01a7..4173332c4 100644 --- a/src/util/gamedata.c +++ b/src/kernel/gamedata.c @@ -1,7 +1,8 @@ #include #include "gamedata.h" -#include "log.h" + +#include #include #include diff --git a/src/util/gamedata.h b/src/kernel/gamedata.h similarity index 90% rename from src/util/gamedata.h rename to src/kernel/gamedata.h index 22c1d9052..1d65f5085 100644 --- a/src/util/gamedata.h +++ b/src/kernel/gamedata.h @@ -36,10 +36,12 @@ #define FAMILIAR_FIX_VERSION 359 /* familiar links are fixed */ #define SKILLSORT_VERSION 360 /* u->skills is sorted */ #define LANDDISPLAY_VERSION 360 /* r.display is now in r.land.display */ -/* unfinished: */ -#define CRYPT_VERSION 400 /* passwords are encrypted */ +#define FIXATKEYS_VERSION 361 /* remove global.attribs, fix at_keys */ +#define FACTION_UID_VERSION 362 /* f->uid contains a database id */ +#define CRYPT_VERSION 363 /* passwords are encrypted */ +#define FAMILIAR_FIXMAGE_VERSION 364 /* familiar links are fixed */ -#define RELEASE_VERSION LANDDISPLAY_VERSION /* current datafile */ +#define RELEASE_VERSION FAMILIAR_FIXMAGE_VERSION /* current datafile */ #define MIN_VERSION UIDHASH_VERSION /* minimal datafile we support */ #define MAX_VERSION RELEASE_VERSION /* change this if we can need to read the future datafile, and we can do so */ diff --git a/src/util/gamedata.test.c b/src/kernel/gamedata.test.c similarity index 100% rename from src/util/gamedata.test.c rename to src/kernel/gamedata.test.c diff --git a/src/kernel/group.c b/src/kernel/group.c index 48434ff5a..210f6e0f2 100755 --- a/src/kernel/group.c +++ b/src/kernel/group.c @@ -30,9 +30,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include /* util includes */ -#include +#include #include -#include +#include #include #include #include @@ -53,7 +53,7 @@ group *new_group(faction * f, const char *name, int gid) { group **gp = &f->groups; int index = gid % GMAXHASH; - group *g = calloc(sizeof(group), 1); + group *g = calloc(1, sizeof(group)); while (*gp) gp = &(*gp)->next; @@ -69,15 +69,7 @@ group *new_group(faction * f, const char *name, int gid) static void init_group(faction * f, group * g) { - ally *a, **an; - - an = &g->allies; - for (a = f->allies; a; a = a->next) - if (a->faction) { - ally *ga = ally_add(an, a->faction); - ga->status = a->status; - an = &ga->next; - } + g->allies = allies_clone(f->allies); } static group *find_groupbyname(group * g, const char *name) @@ -139,11 +131,7 @@ void free_group(group * g) if (g->attribs) { a_removeall(&g->attribs, NULL); } - while (g->allies) { - ally *a = g->allies; - g->allies = a->next; - free(a); - } + allies_free(g->allies); free(g->name); free(g); } @@ -204,20 +192,14 @@ group *join_group(unit * u, const char *name) return g; } -void write_groups(struct storage *store, const faction * f) +void write_groups(struct gamedata *data, const faction * f) { group *g; + storage *store = data->store; for (g = f->groups; g; g = g->next) { - ally *a; WRITE_INT(store, g->gid); WRITE_STR(store, g->name); - for (a = g->allies; a; a = a->next) { - if (a->faction && a->faction->_alive) { - write_faction_reference(a->faction, store); - WRITE_INT(store, a->status); - } - } - write_faction_reference(NULL, store); + write_allies(data, g->allies); a_write(store, g->attribs, g); WRITE_SECTION(store); } @@ -228,7 +210,6 @@ void read_groups(gamedata *data, faction * f) { struct storage *store = data->store; for (;;) { - ally **pa; group *g; int gid; char buf[1024]; @@ -238,19 +219,7 @@ void read_groups(gamedata *data, faction * f) break; READ_STR(store, buf, sizeof(buf)); g = new_group(f, buf, gid); - pa = &g->allies; - for (;;) { - ally *al; - int id; - READ_INT(store, &id); - if (id == 0) break; - al = ally_add(pa, NULL); - al->faction = findfaction(id); - if (!al->faction) { - ur_add(RESOLVE_FACTION | id, (void **)&al->faction, NULL); - } - READ_INT(store, &al->status); - } + read_allies(data, &g->allies); read_attribs(data, &g->attribs, g); } } diff --git a/src/kernel/group.h b/src/kernel/group.h index b257f515a..9b6d97cf9 100755 --- a/src/kernel/group.h +++ b/src/kernel/group.h @@ -30,7 +30,7 @@ extern "C" { struct faction *f; struct attrib *attribs; char *name; - struct ally *allies; + struct allies *allies; int gid; int members; } group; @@ -42,7 +42,7 @@ extern "C" { extern void free_group(struct group *g); struct group *new_group(struct faction * f, const char *name, int gid); - extern void write_groups(struct storage *data, const struct faction *f); + extern void write_groups(struct gamedata *data, const struct faction *f); extern void read_groups(struct gamedata *data, struct faction *f); #ifdef __cplusplus diff --git a/src/kernel/group.test.c b/src/kernel/group.test.c index 5581fee69..7d14380d6 100644 --- a/src/kernel/group.test.c +++ b/src/kernel/group.test.c @@ -8,8 +8,8 @@ #include "region.h" #include "save.h" -#include -#include +#include +#include #include #include @@ -28,22 +28,21 @@ static void test_group_readwrite_dead_faction(CuTest *tc) { faction *f, *f2; unit * u; group *g; - ally *al; int fno; test_setup(); f = test_create_faction(NULL); fno = f->no; CuAssertPtrEquals(tc, f, factions); - CuAssertPtrEquals(tc, 0, f->next); + CuAssertPtrEquals(tc, NULL, f->next); f2 = test_create_faction(NULL); CuAssertPtrEquals(tc, f2, factions->next); u = test_create_unit(f2, test_create_region(0, 0, NULL)); CuAssertPtrNotNull(tc, u); g = join_group(u, "group"); CuAssertPtrNotNull(tc, g); - al = ally_add(&g->allies, f); - CuAssertPtrNotNull(tc, al); + ally_set(&g->allies, f, HELP_GIVE); + CuAssertPtrNotNull(tc, g->allies); CuAssertPtrEquals(tc, f, factions); destroyfaction(&factions); @@ -58,14 +57,14 @@ static void test_group_readwrite_dead_faction(CuTest *tc) { read_game(&data); mstream_done(&data.strm); gamedata_done(&data); - CuAssertPtrEquals(tc, 0, findfaction(fno)); + CuAssertPtrEquals(tc, NULL, findfaction(fno)); f2 = factions; CuAssertPtrNotNull(tc, f2); u = f2->units; CuAssertPtrNotNull(tc, u); g = get_group(u); CuAssertPtrNotNull(tc, g); - CuAssertPtrEquals(tc, 0, g->allies); + CuAssertPtrEquals(tc, NULL, g->allies); test_teardown(); } @@ -73,7 +72,6 @@ static void test_group_readwrite(CuTest * tc) { faction * f; group *g; - ally *al; int i; gamedata data; storage store; @@ -85,9 +83,8 @@ static void test_group_readwrite(CuTest * tc) new_group(f, "NW", 42); g = new_group(f, "Egoisten", 43); key_set(&g->attribs, 44, 44); - al = ally_add(&g->allies, f); - al->status = HELP_GIVE; - write_groups(&store, f); + ally_set(&g->allies, f, HELP_GIVE); + write_groups(&data, f); WRITE_INT(&store, 47); free_group(f->groups); @@ -106,13 +103,11 @@ static void test_group_readwrite(CuTest * tc) CuAssertPtrNotNull(tc, f->groups->next); CuAssertIntEquals(tc, 43, f->groups->next->gid); CuAssertStrEquals(tc, "Egoisten", f->groups->next->name); - CuAssertPtrEquals(tc, 0, f->groups->allies); + CuAssertPtrEquals(tc, NULL, f->groups->allies); g = f->groups->next; CuAssertIntEquals(tc, 44, key_get(g->attribs, 44)); CuAssertPtrNotNull(tc, g->allies); - CuAssertPtrEquals(tc, 0, g->allies->next); - CuAssertPtrEquals(tc, f, g->allies->faction); - CuAssertIntEquals(tc, HELP_GIVE, g->allies->status); + CuAssertIntEquals(tc, HELP_GIVE, ally_get(g->allies, f)); test_teardown(); } @@ -135,7 +130,7 @@ static void test_group(CuTest * tc) CuAssertIntEquals(tc, 1, g->members); set_group(u, 0); CuAssertIntEquals(tc, 0, g->members); - CuAssertPtrEquals(tc, 0, get_group(u)); + CuAssertPtrEquals(tc, NULL, get_group(u)); set_group(u, g); CuAssertIntEquals(tc, 1, g->members); CuAssertPtrEquals(tc, g, get_group(u)); diff --git a/src/kernel/item.c b/src/kernel/item.c index 00f54a656..58702be07 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -35,7 +35,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "unit.h" /* util includes */ -#include +#include #include #include #include diff --git a/src/kernel/item.test.c b/src/kernel/item.test.c index f04a22572..f820f8592 100644 --- a/src/kernel/item.test.c +++ b/src/kernel/item.test.c @@ -61,7 +61,7 @@ static void test_uchange(CuTest * tc, unit * u, const resource_type * rtype) { CuAssertIntEquals(tc, 0, rtype->uchange(u, rtype, -n)); CuAssertPtrNotNull(tc, sl); CuAssertStrEquals(tc, "serious accounting error. number of items is %d.", sl->s); - CuAssertPtrEquals(tc, 0, sl->next); + CuAssertPtrEquals(tc, NULL, sl->next); test_log_stop(log, sl); } @@ -86,7 +86,7 @@ void test_resource_type(CuTest * tc) test_setup(); - CuAssertPtrEquals(tc, 0, rt_find("herpderp")); + CuAssertPtrEquals(tc, NULL, rt_find("herpderp")); test_create_itemtype("herpderp"); test_create_itemtype("herpes"); @@ -122,7 +122,7 @@ void test_findresourcetype(CuTest * tc) locale_setstring(lang, "peasant", "Bauer"); init_resources(); CuAssertPtrNotNull(tc, rt_find("peasant")); - CuAssertPtrEquals(tc, 0, rt_find("log")); + CuAssertPtrEquals(tc, NULL, rt_find("log")); itype = test_create_itemtype("log"); CuAssertPtrEquals(tc, (void*)itype->rtype, (void*)findresourcetype("Holz", lang)); @@ -164,13 +164,13 @@ static void test_core_resources(CuTest *tc) { CuAssertPtrNotNull(tc, rtype->itype); CuAssertPtrNotNull(tc, rtype->uchange); CuAssertPtrNotNull(tc, rtype = rt_find("peasant")); - CuAssertPtrEquals(tc, 0, rtype->itype); + CuAssertPtrEquals(tc, NULL, rtype->itype); CuAssertPtrNotNull(tc, rtype = rt_find("permaura")); - CuAssertPtrEquals(tc, 0, rtype->itype); + CuAssertPtrEquals(tc, NULL, rtype->itype); CuAssertPtrNotNull(tc, rtype = rt_find("hp")); - CuAssertPtrEquals(tc, 0, rtype->itype); + CuAssertPtrEquals(tc, NULL, rtype->itype); CuAssertPtrNotNull(tc, rtype = rt_find("aura")); - CuAssertPtrEquals(tc, 0, rtype->itype); + CuAssertPtrEquals(tc, NULL, rtype->itype); test_teardown(); } diff --git a/src/kernel/messages.h b/src/kernel/messages.h index 723ed2d01..7fa6996e2 100644 --- a/src/kernel/messages.h +++ b/src/kernel/messages.h @@ -26,7 +26,6 @@ extern "C" { #include struct faction; - struct msglevel; typedef struct mlist { struct mlist *next; @@ -39,13 +38,6 @@ extern "C" { void free_messagelist(struct mlist *msgs); - typedef struct msglevel { - /* used to set specialized msg-levels */ - struct msglevel *next; - const struct message_type *type; - int level; - } msglevel; - #define MESSAGE_MISSING_IGNORE 0 #define MESSAGE_MISSING_ERROR 1 #define MESSAGE_MISSING_REPLACE 2 @@ -63,7 +55,7 @@ extern "C" { struct mlist ** merge_messages(message_list *ml, message_list *append); void split_messages(message_list *ml, struct mlist **split); -#define ADDMSG(msgs, mcreate) { message * mx = mcreate; if (mx) { assert(mx->refcount>=1); add_message(msgs, mx); msg_release(mx); } } +#define ADDMSG(msgs, mcreate) { message * mx = mcreate; if (mx) { add_message(msgs, mx); msg_release(mx); } } void syntax_error(const struct unit *u, struct order *ord); void cmistake(const struct unit *u, struct order *ord, int mno, int mtype); diff --git a/src/kernel/messages.test.c b/src/kernel/messages.test.c index 9e66638d9..c186973fa 100644 --- a/src/kernel/messages.test.c +++ b/src/kernel/messages.test.c @@ -74,7 +74,7 @@ static void test_merge_split(CuTest *tc) { add_message(&append, msg = msg_message(mtype->name, "")); msg_release(msg); - CuAssertPtrEquals(tc, 0, mlist->begin->next); + CuAssertPtrEquals(tc, NULL, mlist->begin->next); CuAssertPtrEquals(tc, &mlist->begin->next, mlist->end); split = merge_messages(mlist, append); CuAssertPtrNotNull(tc, split); @@ -83,7 +83,7 @@ static void test_merge_split(CuTest *tc) { CuAssertPtrNotNull(tc, mlist->begin->next); CuAssertPtrEquals(tc, append->begin, mlist->begin->next); split_messages(mlist, split); - CuAssertPtrEquals(tc, 0, mlist->begin->next); + CuAssertPtrEquals(tc, NULL, mlist->begin->next); free_messagelist(*split); free_messagelist(mlist->begin); free(mlist); diff --git a/src/kernel/order.c b/src/kernel/order.c index 8561744dd..493922faa 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -14,13 +14,15 @@ #include #include "order.h" -#include "orderdb.h" +#include "db/driver.h" + #include "skill.h" -#include "keyword.h" #include +#include "util/keyword.h" #include #include +#include #include #include @@ -36,6 +38,52 @@ # define ORD_KEYWORD(ord) (keyword_t)((ord)->command & 0xFFFF) # define OD_STRING(odata) ((odata) ? (odata)->_str : NULL) +order_data *odata_load(int id) +{ + if (id > 0) { + return db_driver_order_load(id); + } + return NULL; +} + +int odata_save(order_data *od) +{ + if (od->_str) { + return db_driver_order_save(od->_str); + } + return 0; +} + +void odata_create(order_data **pdata, size_t len, const char *str) +{ + order_data *data; + char *result; + + assert(pdata); + data = malloc(sizeof(order_data) + len + 1); + data->_refcount = 1; + result = (char *)(data + 1); + data->_str = (len > 0) ? result : NULL; + if (str) { + strcpy(result, str); + } + *pdata = data; +} + +void odata_release(order_data * od) +{ + if (od) { + if (--od->_refcount == 0) { + free(od); + } + } +} + +void odata_addref(order_data *od) +{ + ++od->_refcount; +} + void replace_order(order ** dlist, order * orig, const order * src) { assert(src); @@ -373,7 +421,6 @@ bool is_repeated(keyword_t kwd) case K_ROUTE: case K_DRIVE: case K_WORK: - case K_BESIEGE: case K_ENTERTAIN: case K_TAX: case K_RESEARCH: @@ -414,7 +461,6 @@ bool is_exclusive(const order * ord) case K_ROUTE: case K_DRIVE: case K_WORK: - case K_BESIEGE: case K_ENTERTAIN: case K_TAX: case K_RESEARCH: @@ -456,7 +502,6 @@ bool is_long(keyword_t kwd) case K_ROUTE: case K_DRIVE: case K_WORK: - case K_BESIEGE: case K_ENTERTAIN: case K_TAX: case K_RESEARCH: diff --git a/src/kernel/order.h b/src/kernel/order.h index b0d771b67..ca57d0179 100644 --- a/src/kernel/order.h +++ b/src/kernel/order.h @@ -13,7 +13,8 @@ #ifndef KRNL_ORDER_H #define KRNL_ORDER_H -#include "keyword.h" +#include + #include #include @@ -37,6 +38,18 @@ extern "C" { #define CMD_PERSIST 0x020000 #define CMD_DEFAULT 0x040000 + typedef struct order_data { + const char *_str; + int _refcount; + } order_data; + + extern order_data *odata_load(int id); + extern int odata_save(order_data *od); + + void odata_create(order_data **pdata, size_t len, const char *str); + void odata_release(order_data * od); + void odata_addref(order_data *od); + typedef struct order { struct order *next; /* do not access this data: */ diff --git a/src/kernel/order.test.c b/src/kernel/order.test.c index c4a55177b..14cdeb157 100644 --- a/src/kernel/order.test.c +++ b/src/kernel/order.test.c @@ -5,6 +5,7 @@ #include #include +#include "util/param.h" #include #include @@ -238,11 +239,11 @@ static void test_replace_order(CuTest *tc) { orig = create_order(K_MAKE, lang, NULL); repl = create_order(K_ALLY, lang, NULL); replace_order(&orders, orig, repl); - CuAssertPtrEquals(tc, 0, orders); + CuAssertPtrEquals(tc, NULL, orders); orders = orig; replace_order(&orders, orig, repl); CuAssertPtrNotNull(tc, orders); - CuAssertPtrEquals(tc, 0, orders->next); + CuAssertPtrEquals(tc, NULL, orders->next); CuAssertIntEquals(tc, getkeyword(repl), getkeyword(orders)); free_order(orders); free_order(repl); diff --git a/src/kernel/orderdb.c b/src/kernel/orderdb.c deleted file mode 100644 index b30131be4..000000000 --- a/src/kernel/orderdb.c +++ /dev/null @@ -1,51 +0,0 @@ -#include -#include "database.h" -#include "orderdb.h" - -#include - -#include - -#include -#include -#include - -void odata_create(order_data **pdata, size_t len, const char *str) -{ - order_data *data; - char *result; - - assert(pdata); - data = malloc(sizeof(order_data) + len + 1); - data->_refcount = 1; - result = (char *)(data + 1); - data->_str = (len > 0) ? result : NULL; - if (str) { - strcpy(result, str); - } - *pdata = data; -} - -void odata_release(order_data * od) -{ - if (od) { - if (--od->_refcount == 0) { - free(od); - } - } -} - -void odata_addref(order_data *od) -{ - ++od->_refcount; -} - -order_data *odata_load(int id) -{ - return dblib_load_order(id); -} - -int odata_save(order_data *od) -{ - return dblib_save_order(od); -} diff --git a/src/kernel/orderdb.h b/src/kernel/orderdb.h deleted file mode 100644 index 800732c5e..000000000 --- a/src/kernel/orderdb.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef H_ORDERDB -#define H_ORDERDB - -#include - -#ifdef __cplusplus -extern "C" { -#endif - - typedef struct order_data { - const char *_str; - int _refcount; - } order_data; - - void odata_create(order_data **pdata, size_t len, const char *str); - void odata_release(order_data * od); - void odata_addref(order_data *od); - - order_data *odata_load(int id); - int odata_save(order_data *od); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/src/kernel/orderdb.test.c b/src/kernel/orderdb.test.c deleted file mode 100644 index bdb6f0a95..000000000 --- a/src/kernel/orderdb.test.c +++ /dev/null @@ -1,28 +0,0 @@ -#include -#include - -#include "orderdb.h" - -#include -#include - -#include - -static void test_orderdb(CuTest *tc) { - order_data *od = NULL; - const char * s = "GIB enno 1 Hodor"; - - odata_create(&od, strlen(s) + 1, s); - CuAssertPtrNotNull(tc, od); - CuAssertStrEquals(tc, s, od->_str); - CuAssertTrue(tc, od->_refcount >= 1); - odata_release(od); -} - -CuSuite *get_orderdb_suite(void) -{ - CuSuite *suite = CuSuiteNew(); - SUITE_ADD_TEST(suite, test_orderdb); - - return suite; -} diff --git a/src/kernel/plane.c b/src/kernel/plane.c index 533dab92a..89de42618 100644 --- a/src/kernel/plane.c +++ b/src/kernel/plane.c @@ -25,7 +25,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "faction.h" /* util includes */ -#include +#include #include #include #include @@ -122,7 +122,7 @@ int getplaneid(const region * r) static int ursprung_x(const faction * f, const plane * pl, const region * rdefault) { - ursprung *ur; + origin *ur; int id = 0; if (!f) @@ -131,7 +131,7 @@ ursprung_x(const faction * f, const plane * pl, const region * rdefault) if (pl) id = pl->id; - for (ur = f->ursprung; ur; ur = ur->next) { + for (ur = f->origin; ur; ur = ur->next) { if (ur->id == id) return ur->x; } @@ -145,7 +145,7 @@ ursprung_x(const faction * f, const plane * pl, const region * rdefault) static int ursprung_y(const faction * f, const plane * pl, const region * rdefault) { - ursprung *ur; + origin *ur; int id = 0; if (!f) @@ -154,7 +154,7 @@ ursprung_y(const faction * f, const plane * pl, const region * rdefault) if (pl) id = pl->id; - for (ur = f->ursprung; ur; ur = ur->next) { + for (ur = f->origin; ur; ur = ur->next) { if (ur->id == id) return ur->y; } diff --git a/src/kernel/plane.h b/src/kernel/plane.h index 5b1c71644..faa663a36 100644 --- a/src/kernel/plane.h +++ b/src/kernel/plane.h @@ -28,10 +28,10 @@ extern "C" { struct plane; struct storage; -#define PFL_NOCOORDS 1 /* not in use */ -#define PFL_NORECRUITS 2 -#define PFL_NOALLIANCES 4 -#define PFL_LOWSTEALING 8 +#define PFL_NOCOORDS 1 /* not implemented */ +#define PFL_NORECRUITS 2 /* cannot recruit */ +#define PFL_NOALLIANCES 4 /* not implemented */ +#define PFL_LOWSTEALING 8 /* not implemented */ #define PFL_NOGIVE 16 /* Übergaben sind unmöglich */ #define PFL_NOATTACK 32 /* Angriffe und Diebstähle sind unmöglich */ #define PFL_NOTERRAIN 64 /* Terraintyp wird nicht angezeigt TODO? */ @@ -40,7 +40,7 @@ extern "C" { #define PFL_NOTEACH 512 /* Lehre außer Betrieb */ #define PFL_NOBUILD 1024 /* Bauen außer Betrieb */ #define PFL_NOFEED 2048 /* Kein Unterhalt nötig */ -#define PFL_FRIENDLY 4096 /* everyone is your ally */ +#define PFL_FRIENDLY 4096 /* not implemented */ #define PFL_NOORCGROWTH 8192 /* orcs don't grow */ #define PFL_NOMONSTERS 16384 /* no monster randenc */ diff --git a/src/kernel/plane.test.c b/src/kernel/plane.test.c index 8338cc31f..6eb2ff631 100644 --- a/src/kernel/plane.test.c +++ b/src/kernel/plane.test.c @@ -11,15 +11,15 @@ static void test_plane(CuTest *tc) { test_setup(); r = test_create_region(0, 0, NULL); - CuAssertPtrEquals(tc, 0, findplane(0, 0)); - CuAssertPtrEquals(tc, 0, getplane(r)); + CuAssertPtrEquals(tc, NULL, findplane(0, 0)); + CuAssertPtrEquals(tc, NULL, getplane(r)); CuAssertIntEquals(tc, 0, getplaneid(r)); - CuAssertPtrEquals(tc, 0, getplanebyid(0)); + CuAssertPtrEquals(tc, NULL, getplanebyid(0)); CuAssertIntEquals(tc, 0, plane_center_x(0)); CuAssertIntEquals(tc, 0, plane_center_y(0)); CuAssertIntEquals(tc, 0, plane_width(0)); CuAssertIntEquals(tc, 0, plane_height(0)); - CuAssertPtrEquals(tc, 0, get_homeplane()); + CuAssertPtrEquals(tc, NULL, get_homeplane()); pl = create_new_plane(1, "Hell", 4, 8, 40, 80, 15); r = test_create_region(4, 40, 0); @@ -28,7 +28,7 @@ static void test_plane(CuTest *tc) { CuAssertIntEquals(tc, 8, pl->maxx); CuAssertIntEquals(tc, 40, pl->miny); CuAssertIntEquals(tc, 80, pl->maxy); - CuAssertPtrEquals(tc, 0, pl->attribs); + CuAssertPtrEquals(tc, NULL, pl->attribs); CuAssertStrEquals(tc, "Hell", pl->name); CuAssertPtrEquals(tc, pl, findplane(4, 40)); CuAssertPtrEquals(tc, pl, getplane(r)); diff --git a/src/kernel/pool.c b/src/kernel/pool.c index 52e445c94..70e02cb96 100644 --- a/src/kernel/pool.c +++ b/src/kernel/pool.c @@ -62,7 +62,7 @@ int get_resource(const unit * u, const resource_type * rtype) return get_spellpoints(u); } if (rtype == get_resourcetype(R_PERMAURA)) { - return max_spellpoints(u->region, u); + return max_spellpoints_depr(u->region, u); } log_error("trying to get unknown resource '%s'.\n", rtype->_name); return 0; diff --git a/src/kernel/pool.test.c b/src/kernel/pool.test.c index a3de6c021..10c127f81 100644 --- a/src/kernel/pool.test.c +++ b/src/kernel/pool.test.c @@ -47,7 +47,6 @@ void test_pool(CuTest *tc) { faction *f; region *r; struct resource_type *rtype; - ally *al; test_setup(); test_create_world(); @@ -74,10 +73,9 @@ void test_pool(CuTest *tc) { CuAssertIntEquals(tc, 100, get_pooled(u1, rtype, GET_POOLED_SLACK, INT_MAX)); CuAssertIntEquals(tc, 200, get_pooled(u1, rtype, GET_POOLED_SLACK | GET_POOLED_RESERVE, INT_MAX)); - al = ally_add(&u3->faction->allies, f); - al->status = HELP_GUARD; + ally_set(&u3->faction->allies, f, HELP_GUARD); CuAssertIntEquals(tc, 0, get_pooled(u1, rtype, GET_ALLIED_SLACK | GET_ALLIED_RESERVE, INT_MAX)); - al->status = HELP_MONEY; + ally_set(&u3->faction->allies, f, HELP_MONEY); CuAssertIntEquals(tc, 200, get_pooled(u1, rtype, GET_ALLIED_SLACK, INT_MAX)); CuAssertIntEquals(tc, 200, get_pooled(u1, rtype, GET_ALLIED_RESERVE, INT_MAX)); CuAssertIntEquals(tc, 400, get_pooled(u1, rtype, GET_ALLIED_SLACK | GET_ALLIED_RESERVE, INT_MAX)); @@ -117,7 +115,6 @@ void test_pool_use(CuTest *tc) { faction *f; region *r; struct item_type *itype; - ally *al; test_setup(); test_create_world(); @@ -135,8 +132,7 @@ void test_pool_use(CuTest *tc) { set_resvalue(u2, itype, 100); i_change(&u3->items, itype, 400); set_resvalue(u3, itype, 200); - al = ally_add(&u3->faction->allies, f); - al->status = HELP_MONEY; + ally_set(&u3->faction->allies, f, HELP_MONEY); CuAssertIntEquals(tc, 10, use_pooled(u1, itype->rtype, GET_SLACK, 10)); CuAssertIntEquals(tc, 40, use_pooled(u1, itype->rtype, GET_SLACK, 50)); diff --git a/src/kernel/race.c b/src/kernel/race.c index ecdb7ae3d..53abd339f 100644 --- a/src/kernel/race.c +++ b/src/kernel/race.c @@ -37,7 +37,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "unit.h" /* util includes */ -#include +#include #include #include #include @@ -79,10 +79,10 @@ const char *racenames[MAXRACES] = { "clone" }; -#define MAXOPTIONS 4 +#define MAX_OPTIONS 4 typedef struct rcoption { - unsigned char key[MAXOPTIONS]; - variant value[MAXOPTIONS]; + unsigned char key[MAX_OPTIONS]; + variant value[MAX_OPTIONS]; } rcoption; enum { @@ -106,7 +106,7 @@ static void rc_setoption(race *rc, int k, const char *value) { v = rc->options->value; } else { int i; - for (i=0;!v && i < MAXOPTIONS;++i) { + for (i=0;!v && i < MAX_OPTIONS;++i) { if (rc->options->key[i]==key) { v = rc->options->value+i; break; @@ -114,7 +114,7 @@ static void rc_setoption(race *rc, int k, const char *value) { if (rc->options->key[i]==RCO_NONE) { v = rc->options->value+i; rc->options->key[i] = key; - if (i+1 < MAXOPTIONS) { + if (i+1 < MAX_OPTIONS) { rc->options->key[i+1]=RCO_NONE; } break; @@ -145,7 +145,7 @@ static void rc_setoption(race *rc, int k, const char *value) { static variant *rc_getoption(const race *rc, int key) { if (rc->options) { int i; - for (i=0;i!=MAXOPTIONS && rc->options->key[i]!=RCO_NONE;++i) { + for (i=0;i!=MAX_OPTIONS && rc->options->key[i]!=RCO_NONE;++i) { if (rc->options->key[i]==key) { return rc->options->value+i; } @@ -269,7 +269,7 @@ void free_races(void) { rcoption * opt = races->options; if (opt) { - for (i=0;i!=MAXOPTIONS && opt->key[i]!=RCO_NONE;++i) { + for (i=0;i!=MAX_OPTIONS && opt->key[i]!=RCO_NONE;++i) { if (opt->key[i]==RCO_HUNGER) { free(opt->value[i].v); } @@ -531,14 +531,9 @@ const char *rc_name_s(const race * rc, name_t n) const char *raceprefix(const unit * u) { - attrib *asource = u->faction->attribs; - - if (fval(u, UFL_GROUP)) { - attrib *agroup = a_find(u->attribs, &at_group); - if (agroup != NULL) - asource = ((const group *)(agroup->data.v))->attribs; - } - return get_prefix(asource); + group *g = get_group(u); + attrib *attr = g ? g->attribs : u->faction->attribs; + return get_prefix(attr); } const char *racename(const struct locale *loc, const unit * u, const race * rc) diff --git a/src/kernel/region.c b/src/kernel/region.c index 04c46989c..5d2de2308 100644 --- a/src/kernel/region.c +++ b/src/kernel/region.c @@ -42,8 +42,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* util includes */ #include -#include -#include +#include +#include #include #include #include @@ -242,7 +242,7 @@ static void unhash_uid(region * r) uidhash[key].r = NULL; } -static void hash_uid(region * r) +static void rhash_uid(region * r) { int uid = r->uid; for (;;) { @@ -268,7 +268,7 @@ static int hash_requests; static int hash_misses; #endif -bool pnormalize(int *x, int *y, const plane * pl) +void pnormalize(int *x, int *y, const plane * pl) { if (pl) { if (x) { @@ -284,7 +284,6 @@ bool pnormalize(int *x, int *y, const plane * pl) *y = ny % height + pl->miny; } } - return false; /* TBD */ } static region *rfindhash(int x, int y) @@ -343,8 +342,9 @@ region *r_connect(const region * r, direction_t dir) int x, y; region *rmodify = (region *)r; assert(dir >= 0 && dir < MAXDIRECTIONS); - if (r->connect[dir]) + if (r->connect[dir]) { return r->connect[dir]; + } assert(dir < MAXDIRECTIONS); x = r->x + delta_x[dir]; y = r->y + delta_y[dir]; @@ -757,39 +757,41 @@ int rsettrees(const region * r, int ageclass, int value) return 0; } -static region *last; +region *region_create(int uid) +{ + region *r = (region *)calloc(1, sizeof(region)); + assert_alloc(r); + r->uid = uid; + rhash_uid(r); + return r; +} -static unsigned int max_index = 0; +static region *last; +static unsigned int max_index; + +void add_region(region *r, int x, int y) { + r->x = x; + r->y = y; + r->_plane = findplane(x, y); + rhash(r); + if (last) { + addlist(&last, r); + } + else { + addlist(®ions, r); + } + last = r; + assert(r->next == NULL); + r->index = ++max_index; +} region *new_region(int x, int y, struct plane *pl, int uid) { region *r; - - pnormalize(&x, &y, pl); - r = rfindhash(x, y); - - if (r) { - log_error("duplicate region discovered: %s(%d,%d)\n", regionname(r, NULL), x, y); - if (r->units) - log_error("duplicate region contains units\n"); - return r; - } - r = calloc(1, sizeof(region)); - assert_alloc(r); - r->x = x; - r->y = y; - r->uid = uid; + r = region_create(uid); r->age = 1; - r->_plane = pl; - rhash(r); - hash_uid(r); - if (last) - addlist(&last, r); - else - addlist(®ions, r); - last = r; - assert(r->next == NULL); - r->index = ++max_index; + add_region(r, x, y); + assert(pl == r->_plane); return r; } @@ -1274,7 +1276,7 @@ void resolve_region(region *r) resolve(RESOLVE_REGION | r->uid, r); } -int read_region_reference(gamedata * data, region **rp, resolve_fun fun) +int read_region_reference(gamedata * data, region **rp) { struct storage * store = data->store; int id = 0; @@ -1282,7 +1284,7 @@ int read_region_reference(gamedata * data, region **rp, resolve_fun fun) READ_INT(store, &id); *rp = findregionbyid(id); if (*rp == NULL) { - ur_add(RESOLVE_REGION | id, (void **)rp, fun); + *rp = region_create(id); } return id; } diff --git a/src/kernel/region.h b/src/kernel/region.h index f439bceed..9398919b5 100644 --- a/src/kernel/region.h +++ b/src/kernel/region.h @@ -225,11 +225,13 @@ extern "C" { const char *write_regionname(const struct region *r, const struct faction *f, char *buffer, size_t size); + struct region *region_create(int uid); + void add_region(region *r, int x, int y); struct region *new_region(int x, int y, struct plane *pl, int uid); void remove_region(region ** rlist, region * r); void terraform_region(struct region *r, const struct terrain_type *terrain); void init_region(struct region *r); - bool pnormalize(int *x, int *y, const struct plane *pl); + void pnormalize(int *x, int *y, const struct plane *pl); extern const int delta_x[MAXDIRECTIONS]; extern const int delta_y[MAXDIRECTIONS]; @@ -252,7 +254,7 @@ extern "C" { #define RESOLVE_REGION (TYP_REGION << 24) void resolve_region(region *r); void write_region_reference(const struct region *r, struct storage *store); - int read_region_reference(struct gamedata *data, region **rp, resolve_fun fun); + int read_region_reference(struct gamedata *data, region **rp); const char *regionname(const struct region *r, const struct faction *f); diff --git a/src/kernel/region.test.c b/src/kernel/region.test.c index d54049b8e..4078b7cbd 100644 --- a/src/kernel/region.test.c +++ b/src/kernel/region.test.c @@ -23,14 +23,14 @@ void test_terraform(CuTest *tc) { t_plain = test_create_terrain("plain", LAND_REGION); t_ocean = test_create_terrain("ocean", SEA_REGION); r = test_create_region(0, 0, t_ocean); - CuAssertPtrEquals(tc, 0, r->land); + CuAssertPtrEquals(tc, NULL, r->land); terraform_region(r, t_plain); CuAssertPtrNotNull(tc, r->land); CuAssertPtrNotNull(tc, r->land->demands); CuAssertPtrEquals(tc, itype, (void *)r->land->demands->type->itype); CuAssertIntEquals(tc, 0, r->land->demands->type->price); terraform_region(r, t_ocean); - CuAssertPtrEquals(tc, 0, r->land); + CuAssertPtrEquals(tc, NULL, r->land); test_teardown(); } diff --git a/src/kernel/save.c b/src/kernel/save.c index b51e82734..70f40e0cf 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -57,13 +57,13 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* util includes */ #include -#include +#include #include -#include +#include #include -#include +#include #include -#include +#include #include #include #include @@ -101,9 +101,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* exported symbols symbols */ int firstx = 0, firsty = 0; -/* TODO: is this still important? */ -int enc_gamedata = ENCODING_UTF8; - static void read_alliances(gamedata *data) { storage *store = data->store; @@ -126,7 +123,7 @@ static void read_alliances(gamedata *data) READ_INT(store, &al->flags); } if (data->version >= ALLIANCELEADER_VERSION) { - read_faction_reference(data, &al->_leader, NULL); + read_faction_reference(data, &al->_leader); READ_INT(store, &id); } else { @@ -251,7 +248,7 @@ static void read_owner(gamedata *data, region_owner ** powner) owner->flags = 0; } if (data->version >= OWNER_3_VERSION) { - read_faction_reference(data, &owner->last_owner, NULL); + read_faction_reference(data, &owner->last_owner); } else if (data->version >= OWNER_2_VERSION) { int id; @@ -264,7 +261,7 @@ static void read_owner(gamedata *data, region_owner ** powner) else { owner->last_owner = NULL; } - read_faction_reference(data, &owner->owner, NULL); + read_faction_reference(data, &owner->owner); *powner = owner; } else { @@ -360,14 +357,14 @@ static void read_skills(gamedata *data, unit *u) size_t sz = u->skill_size * sizeof(skill); qsort(skills, u->skill_size, sizeof(skill), skill_cmp); - u->skills = malloc(sz); + u->skills = (skill *)malloc(sz); memcpy(u->skills, skills, sz); } } else { int i; READ_INT(data->store, &u->skill_size); - u->skills = malloc(sizeof(skill)*u->skill_size); + u->skills = (skill *)malloc(sizeof(skill)*u->skill_size); for (i = 0; i != u->skill_size; ++i) { skill *sv = u->skills + i; read_skill(data, sv); @@ -423,10 +420,7 @@ unit *read_unit(gamedata *data) u_setfaction(u, NULL); } else { - u = calloc(sizeof(unit), 1); - assert_alloc(u); - u->no = n; - uhash(u); + u = unit_create(n); } READ_INT(data->store, &n); @@ -443,12 +437,12 @@ unit *read_unit(gamedata *data) if (unicode_utf8_trim(obuf)!=0) { log_warning("trim unit %s name to '%s'", itoa36(u->no), obuf); } - u->_name = obuf[0] ? str_strdup(obuf) : 0; + unit_setname(u, obuf[0] ? obuf : NULL); READ_STR(data->store, obuf, sizeof(obuf)); if (unicode_utf8_trim(obuf)!=0) { log_warning("trim unit %s info to '%s'", itoa36(u->no), obuf); } - u->display = obuf[0] ? str_strdup(obuf) : 0; + unit_setinfo(u, obuf[0] ? obuf : NULL); READ_INT(data->store, &number); set_number(u, number); @@ -547,6 +541,7 @@ unit *read_unit(gamedata *data) void write_unit(gamedata *data, const unit * u) { + const char *str; order *ord; int p = 0; unsigned int flags = u->flags & UFL_SAVEMASK; @@ -556,7 +551,8 @@ void write_unit(gamedata *data, const unit * u) assert(u->faction->_alive); write_faction_reference(u->faction, data->store); WRITE_STR(data->store, u->_name); - WRITE_STR(data->store, u->display ? u->display : ""); + str = unit_getinfo(u); + WRITE_STR(data->store, str ? str : ""); WRITE_INT(data->store, u->number); WRITE_INT(data->store, u->age); WRITE_TOK(data->store, u_race(u)->_name); @@ -618,7 +614,7 @@ static void read_regioninfo(gamedata *data, const region *r, char *info, size_t static region *readregion(gamedata *data, int x, int y) { - region *r = findregion(x, y); + region *r; const terrain_type *terrain; char name[NAMESIZE]; char info[DISPLAYSIZE]; @@ -626,26 +622,19 @@ static region *readregion(gamedata *data, int x, int y) int n; READ_INT(data->store, &uid); - + r = findregionbyid(uid); if (r == NULL) { - plane *pl = findplane(x, y); - r = new_region(x, y, pl, uid); + r = region_create(uid); } else { - assert(uid == 0 || r->uid == uid); - while (r->attribs) - a_remove(&r->attribs, r->attribs); - if (r->land) { - free_land(r->land); - r->land = 0; - } - while (r->resources) { - rawmaterial *rm = r->resources; - r->resources = rm->next; - free(rm); - } - r->land = 0; + /* make sure this was not read earlier */ + assert(r->next == NULL); + assert(r->attribs == NULL); + assert(r->land == NULL); + assert(r->resources == NULL); } + /* add region to the global list: */ + add_region(r, x, y); if (data->version < LANDDISPLAY_VERSION) { read_regioninfo(data, r, info, sizeof(info)); } @@ -924,7 +913,7 @@ static void read_password(gamedata *data, faction *f) { if (name[0] == '$' && data->version == BADCRYPT_VERSION) { char * pass = getpasswd(f->no); if (pass) { - faction_setpassword(f, password_encode(pass, PASSWORD_DEFAULT)); + faction_setpassword(f, password_hash(pass, PASSWORD_DEFAULT)); free(pass); /* TODO: remove this allocation! */ } else { @@ -932,9 +921,8 @@ static void read_password(gamedata *data, faction *f) { } } else { - faction_setpassword(f, (data->version >= CRYPT_VERSION) ? name : password_encode(name, PASSWORD_DEFAULT)); + faction_setpassword(f, (data->version >= CRYPT_VERSION) ? name : password_hash(name, PASSWORD_DEFAULT)); } - (void)_test_read_password; } void _test_read_password(gamedata *data, faction *f) { @@ -942,8 +930,7 @@ void _test_read_password(gamedata *data, faction *f) { } static void write_password(gamedata *data, const faction *f) { - WRITE_TOK(data->store, (const char *)f->_password); - (void)_test_write_password; + WRITE_TOK(data->store, faction_getpassword(f)); } void _test_write_password(gamedata *data, const faction *f) { @@ -960,8 +947,7 @@ faction *read_faction(gamedata * data) assert(n > 0); f = findfaction(n); if (f == NULL) { - f = (faction *)calloc(1, sizeof(faction)); - f->no = n; + f = faction_create(n); } else { f->allies = NULL; /* FIXME: mem leak */ @@ -969,7 +955,10 @@ faction *read_faction(gamedata * data) a_remove(&f->attribs, f->attribs); } } - READ_INT(data->store, &f->subscription); + READ_INT(data->store, &f->uid); + if (data->version < FACTION_UID_VERSION) { + f->uid = 0; + } if (data->version >= SPELL_LEVEL_VERSION) { READ_INT(data->store, &f->max_spelllevel); @@ -1009,7 +998,7 @@ faction *read_faction(gamedata * data) if (unicode_utf8_trim(name)!=0) { log_warning("trim faction %s banner to '%s'", itoa36(f->no), name); }; - f->banner = str_strdup(name); + faction_setbanner(f, name); log_debug(" - Lese Partei %s (%s)", f->name, itoa36(f->no)); @@ -1082,25 +1071,23 @@ faction *read_faction(gamedata * data) /* mistakes were made in the past*/ f->options &= ~WANT_OPTION(O_JSON); } - read_allies(data, f); + read_allies(data, &f->allies); read_groups(data, f); f->spellbook = 0; if (data->version >= REGIONOWNER_VERSION) { read_spellbook(FactionSpells() ? &f->spellbook : 0, data, get_spell_level_faction, (void *)f); } - resolve_faction(f); return f; } void write_faction(gamedata *data, const faction * f) { - ally *sf; - ursprung *ur; + origin *ur; assert(f->_alive); assert(f->no > 0 && f->no <= MAX_UNIT_NR); WRITE_INT(data->store, f->no); - WRITE_INT(data->store, f->subscription); + WRITE_INT(data->store, f->uid); #if RELEASE_VERSION >= SPELL_LEVEL_VERSION WRITE_INT(data->store, f->max_spelllevel); #endif @@ -1117,7 +1104,7 @@ void write_faction(gamedata *data, const faction * f) WRITE_INT(data->store, f->alliance_joindate); WRITE_STR(data->store, f->name); - WRITE_STR(data->store, f->banner); + WRITE_STR(data->store, faction_getbanner(f)); WRITE_STR(data->store, f->email?f->email:""); write_password(data, f); WRITE_TOK(data->store, locale_name(f->locale)); @@ -1134,8 +1121,8 @@ void write_faction(gamedata *data, const faction * f) WRITE_SECTION(data->store); WRITE_TOK(data->store, "end"); WRITE_SECTION(data->store); - WRITE_INT(data->store, listlen(f->ursprung)); - for (ur = f->ursprung; ur; ur = ur->next) { + WRITE_INT(data->store, listlen(f->origin)); + for (ur = f->origin; ur; ur = ur->next) { WRITE_INT(data->store, ur->id); WRITE_INT(data->store, ur->x); WRITE_INT(data->store, ur->y); @@ -1144,23 +1131,9 @@ void write_faction(gamedata *data, const faction * f) WRITE_INT(data->store, f->options & ~WANT_OPTION(O_DEBUG)); WRITE_SECTION(data->store); - for (sf = f->allies; sf; sf = sf->next) { - int no; - int status; - - assert(sf->faction); - - no = sf->faction->no; - status = alliedfaction(NULL, f, sf->faction, HELP_ALL); - - if (status != 0) { - WRITE_INT(data->store, no); - WRITE_INT(data->store, sf->status); - } - } - WRITE_INT(data->store, 0); + write_allies(data, f->allies); WRITE_SECTION(data->store); - write_groups(data->store, f); + write_groups(data, f); write_spellbook(f->spellbook, data->store); } @@ -1320,50 +1293,53 @@ ship *read_ship(gamedata *data) return sh; } +static void fix_fam_triggers(unit *u) { + attrib * a = a_find(u->attribs, &at_mage); + attrib * am = a_find(u->attribs, &at_familiarmage); + if (!am && a) { + /* not a familiar, but magical */ + attrib * ae = a_find(u->attribs, &at_eventhandler); + if (ae) { + trigger **tlist; + tlist = get_triggers(ae, "destroy"); + if (tlist) { + trigger *t; + unit *um = NULL; + for (t = *tlist; t; t = t->next) { + if (t->type == &tt_shock) { + um = (unit *)t->data.v; + break; + } + } + if (um) { + attrib *af = a_find(um->attribs, &at_familiar); + log_error("%s seems to be a broken familiar of %s.", + unitname(u), unitname(um)); + if (af) { + unit * uf = (unit *)af->data.v; + log_error("%s already has a familiar: %s.", + unitname(um), unitname(uf)); + } + else { + set_familiar(um, u); + } + } + else { + log_error("%s seems to be a broken familiar with no trigger.", unitname(u)); + } + } + } + } +} -static void fix_familiars(void) { +static void fix_familiars(void (*callback)(unit *)) { region *r; for (r = regions; r; r = r->next) { unit * u; for (u = r->units; u; u = u->next) { if (u->_race != u->faction->race && (u->_race->flags & RCF_FAMILIAR)) { /* unit is potentially a familiar */ - attrib * a = a_find(u->attribs, &at_mage); - attrib * am = a_find(u->attribs, &at_familiarmage); - if (!am && a) { - /* not a familiar, but magical */ - attrib * ae = a_find(u->attribs, &at_eventhandler); - if (ae) { - trigger **tlist; - tlist = get_triggers(ae, "destroy"); - if (tlist) { - trigger *t; - unit *um = NULL; - for (t = *tlist; t; t = t->next) { - if (t->type == &tt_shock) { - um = (unit *)t->data.v; - break; - } - } - if (um) { - attrib *af = a_find(um->attribs, &at_familiar); - log_error("%s seems to be a broken familiar of %s.", - unitname(u), unitname(um)); - if (af) { - unit * uf = (unit *)af->data.v; - log_error("%s already has a familiar: %s.", - unitname(um), unitname(uf)); - } - else { - set_familiar(um, u); - } - } - else { - log_error("%s seems to be a broken familiar with no trigger.", unitname(u)); - } - } - } - } + callback(u); } } } @@ -1392,7 +1368,13 @@ int read_game(gamedata *data) else { READ_STR(store, NULL, 0); } - read_attribs(data, &global.attribs, NULL); + + if (data->version < FIXATKEYS_VERSION) { + attrib *a = NULL; + read_attribs(data, &a, NULL); + a_removeall(&a, NULL); + } + READ_INT(store, &turn); log_debug(" - reading turn %d", turn); rng_init(turn + config_get_int("game.seed", 0)); @@ -1413,7 +1395,6 @@ int read_game(gamedata *data) *fp = f; fp = &f->next; - fhash(f); } *fp = 0; @@ -1513,22 +1494,21 @@ int read_game(gamedata *data) } } else { + assert(f->units); for (u = f->units; u; u = u->nextF) { if (data->version < SPELL_LEVEL_VERSION) { - sc_mage *mage = get_mage_depr(u); + struct sc_mage *mage = get_mage(u); if (mage) { faction *f = u->faction; int skl = effskill(u, SK_MAGIC, 0); if (f->magiegebiet == M_GRAY) { - log_error("faction %s had magic=gray, fixing (%s)", factionname(f), magic_school[mage->magietyp]); - f->magiegebiet = mage->magietyp; + f->magiegebiet = mage_get_type(mage); + log_error("faction %s had magic=gray, fixing (%s)", + factionname(f), magic_school[f->magiegebiet]); } if (f->max_spelllevel < skl) { f->max_spelllevel = skl; } - if (mage->spellcount < 0) { - mage->spellcount = 0; - } } } if (u->number > 0) { @@ -1545,7 +1525,10 @@ int read_game(gamedata *data) } if (data->version < FAMILIAR_FIX_VERSION) { - fix_familiars(); + fix_familiars(fix_fam_triggers); + } + if (data->version < FAMILIAR_FIXMAGE_VERSION) { + fix_familiars(fix_fam_mage); } log_debug("Done loading turn %d.", turn); @@ -1614,9 +1597,6 @@ int write_game(gamedata *data) { WRITE_INT(store, game_id()); WRITE_SECTION(store); - write_attribs(store, global.attribs, NULL); - WRITE_SECTION(store); - WRITE_INT(store, turn); WRITE_INT(store, 0 /* max_unique_id */); WRITE_INT(store, nextborder); @@ -1678,6 +1658,5 @@ int write_game(gamedata *data) { WRITE_SECTION(store); write_borders(store); WRITE_SECTION(store); - return 0; } diff --git a/src/kernel/save.test.c b/src/kernel/save.test.c index 4e6e0e2d4..e069d7ebf 100644 --- a/src/kernel/save.test.c +++ b/src/kernel/save.test.c @@ -17,10 +17,10 @@ #include #include #include -#include +#include #include -#include -#include +#include +#include #include #include #include @@ -86,7 +86,7 @@ static void test_readwrite_unit(CuTest * tc) CuAssertPtrEquals(tc, f, u->faction); CuAssertStrEquals(tc, "Hodor", u->_name); CuAssertTrue(tc, irace == u_irace(u)); - CuAssertPtrEquals(tc, 0, u->region); + CuAssertPtrEquals(tc, NULL, u->region); mstream_done(&data.strm); gamedata_done(&data); @@ -115,7 +115,7 @@ static void test_readwrite_faction(CuTest * tc) f = read_faction(&data); CuAssertPtrNotNull(tc, f); CuAssertStrEquals(tc, "Hodor", f->name); - CuAssertPtrEquals(tc, 0, f->units); + CuAssertPtrEquals(tc, NULL, f->units); factions = f; mstream_done(&data.strm); @@ -179,7 +179,7 @@ static void test_readwrite_building(CuTest * tc) b = read_building(&data); CuAssertPtrNotNull(tc, b); CuAssertStrEquals(tc, "Hodor", b->name); - CuAssertPtrEquals(tc, 0, b->region); + CuAssertPtrEquals(tc, NULL, b->region); b->region = r; r->buildings = b; @@ -212,7 +212,7 @@ static void test_readwrite_ship(CuTest * tc) sh = read_ship(&data); CuAssertPtrNotNull(tc, sh); CuAssertStrEquals(tc, "Hodor", sh->name); - CuAssertPtrEquals(tc, 0, sh->region); + CuAssertPtrEquals(tc, NULL, sh->region); sh->region = r; r->ships = sh; @@ -233,7 +233,7 @@ static void test_readwrite_attrib(CuTest *tc) { gamedata_init(&data, &store, RELEASE_VERSION); write_attribs(data.store, a, NULL); a_removeall(&a, NULL); - CuAssertPtrEquals(tc, 0, a); + CuAssertPtrEquals(tc, NULL, a); data.strm.api->rewind(data.strm.handle); read_attribs(&data, &a, NULL); @@ -250,7 +250,6 @@ static void test_readwrite_dead_faction_group(CuTest *tc) { faction *f, *f2; unit * u; group *g; - ally *al; int fno; gamedata data; storage store; @@ -262,15 +261,16 @@ static void test_readwrite_dead_faction_group(CuTest *tc) { f = test_create_faction(NULL); fno = f->no; CuAssertPtrEquals(tc, f, factions); - CuAssertPtrEquals(tc, 0, f->next); + CuAssertPtrEquals(tc, NULL, f->next); f2 = test_create_faction(NULL); CuAssertPtrEquals(tc, f2, factions->next); u = test_create_unit(f2, test_create_region(0, 0, NULL)); CuAssertPtrNotNull(tc, u); g = join_group(u, "group"); CuAssertPtrNotNull(tc, g); - al = ally_add(&g->allies, f); - CuAssertPtrNotNull(tc, al); + CuAssertPtrEquals(tc, NULL, g->allies); + ally_set(&g->allies, f, HELP_GIVE); + CuAssertPtrNotNull(tc, g->allies); CuAssertPtrEquals(tc, f, factions); destroyfaction(&factions); @@ -281,14 +281,14 @@ static void test_readwrite_dead_faction_group(CuTest *tc) { f = f2 = NULL; data.strm.api->rewind(data.strm.handle); read_game(&data); - CuAssertPtrEquals(tc, 0, findfaction(fno)); + CuAssertPtrEquals(tc, NULL, findfaction(fno)); f2 = factions; CuAssertPtrNotNull(tc, f2); u = f2->units; CuAssertPtrNotNull(tc, u); g = get_group(u); CuAssertPtrNotNull(tc, g); - CuAssertPtrEquals(tc, 0, g->allies); + CuAssertPtrEquals(tc, NULL, g->allies); mstream_done(&data.strm); gamedata_done(&data); test_teardown(); @@ -319,10 +319,10 @@ static void test_readwrite_dead_faction_regionowner(CuTest *tc) { mstream_done(&data.strm); gamedata_done(&data); f = factions; - CuAssertPtrEquals(tc, 0, f); + CuAssertPtrEquals(tc, NULL, f); r = regions; CuAssertPtrNotNull(tc, r); - CuAssertPtrEquals(tc, 0, region_get_owner(r)); + CuAssertPtrEquals(tc, NULL, region_get_owner(r)); test_teardown(); } @@ -359,7 +359,7 @@ static void test_readwrite_dead_faction_changefaction(CuTest *tc) { CuAssertPtrNotNull(tc, r); u = r->units; CuAssertPtrNotNull(tc, u); - CuAssertPtrEquals(tc, 0, a_find(u->attribs, &at_eventhandler)); + CuAssertPtrEquals(tc, NULL, a_find(u->attribs, &at_eventhandler)); test_teardown(); } @@ -396,7 +396,7 @@ static void test_readwrite_dead_faction_createunit(CuTest *tc) { CuAssertPtrNotNull(tc, r); u = r->units; CuAssertPtrNotNull(tc, u); - CuAssertPtrEquals(tc, 0, a_find(u->attribs, &at_eventhandler)); + CuAssertPtrEquals(tc, NULL, a_find(u->attribs, &at_eventhandler)); test_teardown(); } @@ -407,7 +407,7 @@ static void test_read_password(CuTest *tc) { test_setup(); f = test_create_faction(NULL); - faction_setpassword(f, password_encode("secret", PASSWORD_DEFAULT)); + faction_setpassword(f, password_hash("secret", PASSWORD_DEFAULT)); mstream_init(&data.strm); gamedata_init(&data, &store, RELEASE_VERSION); _test_write_password(&data, f); @@ -431,8 +431,8 @@ static void test_read_password_external(CuTest *tc) { errno = 0; } f = test_create_faction(NULL); - faction_setpassword(f, password_encode("secret", PASSWORD_DEFAULT)); - CuAssertPtrNotNull(tc, f->_password); + faction_setpassword(f, password_hash("secret", PASSWORD_DEFAULT)); + CuAssertPtrNotNull(tc, faction_getpassword(f)); mstream_init(&data.strm); gamedata_init(&data, &store, RELEASE_VERSION); WRITE_TOK(data.store, "newpassword"); @@ -441,16 +441,15 @@ static void test_read_password_external(CuTest *tc) { data.strm.api->rewind(data.strm.handle); data.version = NOCRYPT_VERSION; _test_read_password(&data, f); - CuAssertStrEquals(tc, "newpassword", f->_password); + CuAssertTrue(tc, checkpasswd(f, "newpassword")); data.version = BADCRYPT_VERSION; _test_read_password(&data, f); - CuAssertStrEquals(tc, "secret", f->_password); + CuAssertTrue(tc, checkpasswd(f, "secret")); F = fopen(pwfile, "wt"); fprintf(F, "%s:pwfile\n", itoa36(f->no)); fclose(F); CuAssertTrue(tc, checkpasswd(f, "secret")); _test_read_password(&data, f); - CuAssertStrEquals(tc, "pwfile", f->_password); CuAssertTrue(tc, checkpasswd(f, "pwfile")); mstream_done(&data.strm); gamedata_done(&data); diff --git a/src/kernel/ship.c b/src/kernel/ship.c index 4719945b0..6fcea4935 100644 --- a/src/kernel/ship.c +++ b/src/kernel/ship.c @@ -34,12 +34,13 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "skill.h" /* util includes */ -#include +#include #include -#include +#include #include #include #include +#include #include #include diff --git a/src/kernel/ship.test.c b/src/kernel/ship.test.c index 074876dd5..180b558a2 100644 --- a/src/kernel/ship.test.c +++ b/src/kernel/ship.test.c @@ -7,7 +7,7 @@ #include #include -#include +#include #include #include @@ -278,7 +278,7 @@ static void test_shipowner_goes_to_same_faction_after_leave(CuTest * tc) leave_ship(u3); CuAssertPtrEquals(tc, u2, ship_owner(sh)); leave_ship(u2); - CuAssertPtrEquals(tc, 0, ship_owner(sh)); + CuAssertPtrEquals(tc, NULL, ship_owner(sh)); test_teardown(); } @@ -311,7 +311,7 @@ static void test_shipowner_resets_when_empty(CuTest * tc) u_set_ship(u, sh); CuAssertPtrEquals(tc, u, ship_owner(sh)); u->number = 0; - CuAssertPtrEquals(tc, 0, ship_owner(sh)); + CuAssertPtrEquals(tc, NULL, ship_owner(sh)); u->number = 1; CuAssertPtrEquals(tc, u, ship_owner(sh)); test_teardown(); @@ -353,7 +353,7 @@ void test_shipowner_goes_to_empty_unit_after_leave(CuTest * tc) leave_ship(u1); CuAssertPtrEquals(tc, u3, ship_owner(sh)); leave_ship(u3); - CuAssertPtrEquals(tc, 0, ship_owner(sh)); + CuAssertPtrEquals(tc, NULL, ship_owner(sh)); u2->number = 1; CuAssertPtrEquals(tc, u2, ship_owner(sh)); test_teardown(); @@ -365,8 +365,8 @@ static void test_stype_defaults(CuTest *tc) { stype = st_get_or_create("hodor"); CuAssertPtrNotNull(tc, stype); CuAssertStrEquals(tc, "hodor", stype->_name); - CuAssertPtrEquals(tc, 0, stype->construction); - CuAssertPtrEquals(tc, 0, stype->coasts); + CuAssertPtrEquals(tc, NULL, stype->construction); + CuAssertPtrEquals(tc, NULL, stype->coasts); CuAssertDblEquals(tc, 0.0, stype->damage, 0.0); CuAssertDblEquals(tc, 1.0, stype->storm, 0.0); CuAssertDblEquals(tc, 1.0, stype->tac_bonus, 0.01); diff --git a/src/kernel/skills.c b/src/kernel/skills.c index a15fb4463..ea2022872 100644 --- a/src/kernel/skills.c +++ b/src/kernel/skills.c @@ -24,7 +24,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "region.h" #include "unit.h" -#include +#include #include #include #include diff --git a/src/kernel/spell.test.c b/src/kernel/spell.test.c index 025584114..027a57079 100644 --- a/src/kernel/spell.test.c +++ b/src/kernel/spell.test.c @@ -17,8 +17,8 @@ static void test_create_a_spell(CuTest * tc) spell * sp; test_setup(); - CuAssertPtrEquals(tc, 0, spells); - CuAssertPtrEquals(tc, 0, find_spell("testspell")); + CuAssertPtrEquals(tc, NULL, spells); + CuAssertPtrEquals(tc, NULL, find_spell("testspell")); sp = create_spell("testspell"); CuAssertPtrEquals(tc, sp, find_spell("testspell")); @@ -36,13 +36,13 @@ static void test_create_duplicate_spell(CuTest * tc) test_log_stderr(0); /* suppress the "duplicate spell" error message */ log = test_log_start(LOG_CPERROR, &sl); - CuAssertPtrEquals(tc, 0, find_spell("testspell")); + CuAssertPtrEquals(tc, NULL, find_spell("testspell")); sp = create_spell("testspell"); - CuAssertPtrEquals(tc, 0, create_spell("testspell")); + CuAssertPtrEquals(tc, NULL, create_spell("testspell")); CuAssertPtrNotNull(tc, sl); CuAssertStrEquals(tc, "create_spell: duplicate name '%s'", sl->s); - CuAssertPtrEquals(tc, 0, sl->next); + CuAssertPtrEquals(tc, NULL, sl->next); CuAssertPtrEquals(tc, sp, find_spell("testspell")); test_log_stop(log, sl); test_log_stderr(1); /* or teardown complains that stderr logging is off */ diff --git a/src/kernel/spellbook.c b/src/kernel/spellbook.c index 868f9757c..d230992cf 100644 --- a/src/kernel/spellbook.c +++ b/src/kernel/spellbook.c @@ -4,7 +4,7 @@ #include #include -#include +#include #include #include "spellbook.h" diff --git a/src/kernel/spellbook.test.c b/src/kernel/spellbook.test.c index 22ea7c491..d83409797 100644 --- a/src/kernel/spellbook.test.c +++ b/src/kernel/spellbook.test.c @@ -25,7 +25,7 @@ void test_named_spellbooks(CuTest * tc) sb = create_spellbook(0); CuAssertPtrNotNull(tc, sb); - CuAssertPtrEquals(tc, 0, sb->name); + CuAssertPtrEquals(tc, NULL, sb->name); spellbook_clear(sb); free(sb); diff --git a/src/kernel/terrain.c b/src/kernel/terrain.c index c7e007891..bec8fa8e8 100644 --- a/src/kernel/terrain.c +++ b/src/kernel/terrain.c @@ -30,7 +30,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "terrainid.h" #include -#include +#include #include /* libc includes */ diff --git a/src/kernel/types.h b/src/kernel/types.h index 48a4326fa..2b014bc94 100644 --- a/src/kernel/types.h +++ b/src/kernel/types.h @@ -55,12 +55,6 @@ struct terrain_type; struct unit; struct weapon_type; -typedef struct ursprung { - struct ursprung *next; - int id; - int x, y; -} ursprung; - /* seen_mode: visibility in the report */ typedef enum { seen_none, @@ -83,58 +77,6 @@ typedef enum { ST_FLEE } status_t; -/* ----------------- Parameter --------------------------------- */ - -typedef enum { - P_LOCALE, - P_ANY, - P_EACH, - P_PEASANT, - P_BUILDING, - P_UNIT, - P_PRIVAT, - P_BEHIND, - P_CONTROL, - P_HERBS, - P_NOT, - P_NEXT, - P_FACTION, - P_GAMENAME, - P_PERSON, - P_REGION, - P_SHIP, - P_MONEY, - P_ROAD, - P_TEMP, - P_FLEE, - P_GEBAEUDE, - P_GIVE, - P_FIGHT, - P_TRAVEL, - P_GUARD, - P_ZAUBER, - P_PAUSE, - P_VORNE, - P_AGGRO, - P_CHICKEN, - P_LEVEL, - P_HELP, - P_FOREIGN, - P_AURA, - P_AFTER, - P_BEFORE, - P_NUMBER, - P_ITEMS, - P_POTIONS, - P_GROUP, - P_FACTIONSTEALTH, - P_TREES, - P_ALLIANCE, - P_AUTO, - MAXPARAMS, - NOPARAM -} param_t; - typedef enum { /* Fehler und Meldungen im Report */ MSG_BATTLE, MSG_EVENT, @@ -156,8 +98,6 @@ enum { /* Message-Level */ ML_MAX }; -extern const char *parameters[MAXPARAMS]; - /* --------------- Reports Typen ------------------------------- */ enum { @@ -177,7 +117,7 @@ enum { MAXOPTIONS }; -typedef enum { +typedef enum magic_t { M_GRAY = 0, /* Gray */ M_ILLAUN = 1, /* Illaun */ M_TYBIED = 2, /* Tybied */ diff --git a/src/kernel/unit.c b/src/kernel/unit.c index b63e8beb8..748c76003 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -21,12 +21,16 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "unit.h" #include "ally.h" +#include "attrib.h" #include "building.h" #include "calendar.h" -#include "faction.h" -#include "group.h" #include "connection.h" #include "curse.h" +#include "event.h" +#include "faction.h" +#include "gamedata.h" +#include "group.h" +#include "guard.h" #include "item.h" #include "move.h" #include "order.h" @@ -47,18 +51,13 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include -#include "guard.h" - /* util includes */ -#include #include -#include -#include -#include #include #include #include #include +#include #include #include #include @@ -209,6 +208,7 @@ static buddy *get_friends(const unit * u, int *numfriends) nf = *fr; if (nf == NULL || nf->faction != u2->faction) { nf = malloc(sizeof(buddy)); + assert(nf); nf->next = *fr; nf->faction = u2->faction; nf->unit = u2; @@ -431,7 +431,7 @@ unit *findnewunit(const region * r, const faction * f, int n) /*********************/ /* at_alias */ /*********************/ -attrib_type at_alias = { +static attrib_type at_alias = { "alias", DEFAULT_INIT, DEFAULT_FINALIZE, @@ -452,6 +452,11 @@ int ualias(const unit * u) return a->data.i; } +void usetalias(unit *u, int alias) +{ + a_add(&u->attribs, a_new(&at_alias))->data.i = alias; +} + int a_readprivate(variant *var, void *owner, gamedata *data) { struct storage *store = data->store; @@ -475,8 +480,8 @@ attrib_type at_private = { const char *u_description(const unit * u, const struct locale *lang) { - if (u->display && u->display[0]) { - return u->display; + if (u->display_id > 0) { + return unit_getinfo(u); } else { char zText[64]; @@ -518,112 +523,6 @@ void usetprivate(unit * u, const char *str) a->data.v = str_strdup(str); } -/*********************/ -/* at_target */ -/*********************/ -attrib_type at_target = { - "target", - DEFAULT_INIT, - DEFAULT_FINALIZE, - DEFAULT_AGE, - NO_WRITE, - NO_READ -}; - -/*********************/ -/* at_siege */ -/*********************/ - -void a_writesiege(const variant *var, const void *owner, struct storage *store) -{ - struct building *b = (struct building *)var->v; - write_building_reference(b, store); -} - -int a_readsiege(variant *var, void *owner, gamedata *data) -{ - if (read_building_reference(data, (building **)&var->v, NULL) <= 0) { - return AT_READ_FAIL; - } - return AT_READ_OK; -} - -attrib_type at_siege = { - "siege", - DEFAULT_INIT, - DEFAULT_FINALIZE, - DEFAULT_AGE, - a_writesiege, - a_readsiege -}; - -struct building *usiege(const unit * u) -{ - attrib *a; - if (!fval(u, UFL_SIEGE)) - return NULL; - a = a_find(u->attribs, &at_siege); - assert(a || !"flag set, but no siege found"); - return (struct building *)a->data.v; -} - -void usetsiege(unit * u, const struct building *t) -{ - attrib *a = a_find(u->attribs, &at_siege); - if (!a && t) - a = a_add(&u->attribs, a_new(&at_siege)); - if (a) { - if (!t) { - a_remove(&u->attribs, a); - freset(u, UFL_SIEGE); - } - else { - a->data.v = (void *)t; - fset(u, UFL_SIEGE); - } - } -} - -/*********************/ -/* at_contact */ -/*********************/ -attrib_type at_contact = { - "contact", - DEFAULT_INIT, - DEFAULT_FINALIZE, - DEFAULT_AGE, - NO_WRITE, - NO_READ -}; - -void usetcontact(unit * u, const unit * u2) -{ - attrib *a = a_find(u->attribs, &at_contact); - while (a && a->type == &at_contact && a->data.v != u2) - a = a->next; - if (a && a->type == &at_contact) - return; - a_add(&u->attribs, a_new(&at_contact))->data.v = (void *)u2; -} - -bool ucontact(const unit * u, const unit * u2) -/* Prueft, ob u den Kontaktiere-Befehl zu u2 gesetzt hat. */ -{ - attrib *ru; - if (u->faction == u2->faction) - return true; - - /* Explizites KONTAKTIERE */ - for (ru = a_find(u->attribs, &at_contact); ru && ru->type == &at_contact; - ru = ru->next) { - if (((unit *)ru->data.v) == u2) { - return true; - } - } - - return false; -} - /*** ** init & cleanup module **/ @@ -1106,11 +1005,15 @@ skill *add_skill(unit * u, skill_t sk) skill *sv; int i; + assert(u); for (i = 0; i != u->skill_size; ++i) { sv = u->skills + i; if (sv->id >= sk) break; } - u->skills = realloc(u->skills, (1 + u->skill_size) * sizeof(skill)); + sv = realloc(u->skills, (1 + u->skill_size) * sizeof(skill)); + assert(sv); + u->skills = sv; + sv = u->skills + i; if (i < u->skill_size) { assert(sv->id != sk); @@ -1346,25 +1249,30 @@ int invisible(const unit * target, const unit * viewer) */ void free_unit(unit * u) { + struct reservation **pres = &u->reservations; + assert(!u->region); free(u->_name); - free(u->display); free_order(u->thisorder); free_orders(&u->orders); - if (u->skills) + + while (*pres) { + struct reservation *res = *pres; + *pres = res->next; + free(res); + } + if (u->skills) { free(u->skills); + u->skills = NULL; + } while (u->items) { item *it = u->items->next; u->items->next = NULL; i_free(u->items); u->items = it; } - while (u->attribs) + while (u->attribs) { a_remove(&u->attribs, u->attribs); - while (u->reservations) { - struct reservation *res = u->reservations; - u->reservations = res->next; - free(res); } } @@ -1431,6 +1339,12 @@ void name_unit(unit * u) } } +unit *unit_create(int id) +{ + unit *u = (unit *)calloc(1, sizeof(unit)); + createunitid(u, id); + return u; +} /** creates a new unit. * * @param dname: name, set to NULL to get a default. @@ -1439,7 +1353,7 @@ void name_unit(unit * u) unit *create_unit(region * r, faction * f, int number, const struct race *urace, int id, const char *dname, unit * creator) { - unit *u = (unit *)calloc(1, sizeof(unit)); + unit *u = unit_create(id); assert(urace); u_setrace(u, urace); @@ -1451,10 +1365,6 @@ unit *create_unit(region * r, faction * f, int number, const struct race *urace, set_number(u, number); - /* die nummer der neuen einheit muss vor name_unit generiert werden, - * da der default name immer noch 'Nummer u->no' ist */ - createunitid(u, id); - /* zuerst in die Region setzen, da zb Drachennamen den Regionsnamen * enthalten */ if (r) @@ -1510,10 +1420,9 @@ unit *create_unit(region * r, faction * f, int number, const struct race *urace, } /* Gruppen */ - if (creator->faction == f && fval(creator, UFL_GROUP)) { - a = a_find(creator->attribs, &at_group); - if (a) { - group *g = (group *)a->data.v; + if (creator->faction == f) { + group *g = get_group(creator); + if (g) { set_group(u, g); } } @@ -1577,16 +1486,20 @@ void unit_setname(unit * u, const char *name) const char *unit_getinfo(const unit * u) { - return (const char *)u->display; + if (u->display_id > 0) { + return dbstring_load(u->display_id, NULL); + } + return NULL; } void unit_setinfo(unit * u, const char *info) { - free(u->display); - if (info) - u->display = str_strdup(info); - else - u->display = NULL; + if (info) { + u->display_id = dbstring_save(info); + } + else { + u->display_id = 0; + } } int unit_getid(const unit * u) @@ -1744,34 +1657,6 @@ void u_setrace(struct unit *u, const struct race *rc) } } -void unit_add_spell(unit * u, sc_mage * m, struct spell * sp, int level) -{ - sc_mage *mage = m ? m : get_mage_depr(u); - - if (!mage) { - log_debug("adding new spell %s to a previously non-mage unit %s\n", sp->sname, unitname(u)); - mage = create_mage(u, u->faction ? u->faction->magiegebiet : M_GRAY); - } - if (!mage->spellbook) { - mage->spellbook = create_spellbook(0); - } - spellbook_add(mage->spellbook, sp, level); -} - -struct spellbook * unit_get_spellbook(const struct unit * u) -{ - sc_mage * mage = get_mage_depr(u); - if (mage) { - if (mage->spellbook) { - return mage->spellbook; - } - if (mage->magietyp != M_GRAY) { - return faction_get_spellbook(u->faction); - } - } - return 0; -} - int effskill(const unit * u, skill_t sk, const region *r) { assert(u); @@ -1910,14 +1795,6 @@ int getunit(const region * r, const faction * f, unit **uresult) return result; } -int besieged(const unit * u) -{ - /* belagert kann man in schiffen und burgen werden */ - return (u && !keyword_disabled(K_BESIEGE) - && u->building && u->building->besieged - && u->building->besieged >= u->building->size * SIEGEFACTOR); -} - bool has_horses(const unit * u) { item *itm = u->items; diff --git a/src/kernel/unit.h b/src/kernel/unit.h index 0b0e9da6f..930574629 100644 --- a/src/kernel/unit.h +++ b/src/kernel/unit.h @@ -21,6 +21,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include "types.h" +#include "database.h" #include "skills.h" #include @@ -47,7 +48,6 @@ extern "C" { #define UFL_NOTMOVING (1<<9) /* Die Einheit kann sich wg. langen Kampfes nicht bewegen */ #define UFL_DEFENDER (1<<10) #define UFL_HUNGER (1<<11) /* kann im Folgemonat keinen langen Befehl außer ARBEITE ausführen */ -#define UFL_SIEGE (1<<12) /* speedup: belagert eine burg, siehe attribut */ #define UFL_TARGET (1<<13) /* speedup: hat ein target, siehe attribut */ #define UFL_WERE (1<<14) #define UFL_ENTER (1<<15) /* unit has entered a ship/building and will not leave it */ @@ -90,7 +90,7 @@ extern "C" { int no; /* id */ int hp; char *_name; - char *display; + dbrow_id display_id; struct faction *faction; struct building *building; struct ship *ship; @@ -120,16 +120,14 @@ extern "C" { } unit; extern struct attrib_type at_creator; - extern struct attrib_type at_alias; - extern struct attrib_type at_siege; - extern struct attrib_type at_target; extern struct attrib_type at_potionuser; - extern struct attrib_type at_contact; extern struct attrib_type at_effect; extern struct attrib_type at_private; extern struct attrib_type at_showskchange; int ualias(const struct unit *u); + void usetalias(unit *u, int alias); + int weight(const struct unit *u); void renumber_unit(struct unit *u, int no); @@ -138,15 +136,10 @@ extern "C" { const struct race *u_irace(const struct unit *u); const struct race *u_race(const struct unit *u); void u_setrace(struct unit *u, const struct race *); - struct building *usiege(const struct unit *u); - void usetsiege(struct unit *u, const struct building *b); const char *uprivate(const struct unit *u); void usetprivate(struct unit *u, const char *c); - bool ucontact(const struct unit *u, const struct unit *u2); - void usetcontact(struct unit *u, const struct unit *c); - struct unit *findnewunit(const struct region *r, const struct faction *f, int alias); @@ -209,10 +202,11 @@ extern "C" { int invisible(const struct unit *target, const struct unit *viewer); void free_unit(struct unit *u); - extern void name_unit(struct unit *u); - extern struct unit *create_unit(struct region *r1, struct faction *f, + void name_unit(struct unit *u); + struct unit *unit_create(int id); + struct unit *create_unit(struct region *r1, struct faction *f, int number, const struct race *rc, int id, const char *dname, - struct unit *creator); + struct unit *creator); void uhash(struct unit *u); void uunhash(struct unit *u); @@ -234,8 +228,6 @@ extern "C" { int unit_max_hp(const struct unit *u); void scale_number(struct unit *u, int n); - struct spellbook * unit_get_spellbook(const struct unit * u); - void unit_add_spell(struct unit * u, struct sc_mage * m, struct spell * sp, int level); void remove_empty_units_in_region(struct region * r); void remove_empty_units(void); @@ -256,7 +248,6 @@ extern "C" { int read_unitid(const struct faction *f, const struct region *r); /* !< sets combatstatus of a unit */ - int besieged(const struct unit *u); bool has_horses(const struct unit *u); int maintenance_cost(const struct unit *u); bool has_limited_skills(const struct unit *u); diff --git a/src/kernel/unit.test.c b/src/kernel/unit.test.c index 4b0ba2af6..0918e83aa 100644 --- a/src/kernel/unit.test.c +++ b/src/kernel/unit.test.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include #include @@ -42,7 +42,7 @@ static void test_remove_empty_units(CuTest *tc) { CuAssertPtrNotNull(tc, findunit(uid)); u->number = 0; remove_empty_units(); - CuAssertPtrEquals(tc, 0, findunit(uid)); + CuAssertPtrEquals(tc, NULL, findunit(uid)); test_teardown(); } @@ -61,9 +61,9 @@ static void test_remove_empty_units_in_region(CuTest *tc) { CuAssertPtrNotNull(tc, findunit(uid)); u->number = 0; remove_empty_units_in_region(u->region); - CuAssertPtrEquals(tc, 0, findunit(uid)); - CuAssertPtrEquals(tc, 0, u->nextF); - CuAssertPtrEquals(tc, 0, u->region); + CuAssertPtrEquals(tc, NULL, findunit(uid)); + CuAssertPtrEquals(tc, NULL, u->nextF); + CuAssertPtrEquals(tc, NULL, u->region); test_teardown(); } @@ -78,7 +78,7 @@ static void test_remove_units_without_faction(CuTest *tc) { uid = u->no; u_setfaction(u, 0); remove_empty_units_in_region(u->region); - CuAssertPtrEquals(tc, 0, findunit(uid)); + CuAssertPtrEquals(tc, NULL, findunit(uid)); CuAssertIntEquals(tc, 0, u->number); test_teardown(); } @@ -94,7 +94,7 @@ static void test_remove_units_with_dead_faction(CuTest *tc) { uid = u->no; u->faction->_alive = false; remove_empty_units_in_region(u->region); - CuAssertPtrEquals(tc, 0, findunit(uid)); + CuAssertPtrEquals(tc, NULL, findunit(uid)); CuAssertIntEquals(tc, 0, u->number); test_teardown(); } @@ -308,16 +308,16 @@ static void test_inside_building(CuTest *tc) { b->size = 1; scale_number(u, 1); - CuAssertPtrEquals(tc, 0, inside_building(u)); + CuAssertPtrEquals(tc, NULL, inside_building(u)); u->building = b; CuAssertPtrEquals(tc, b, inside_building(u)); scale_number(u, 2); - CuAssertPtrEquals(tc, 0, inside_building(u)); + CuAssertPtrEquals(tc, NULL, inside_building(u)); b->size = 2; CuAssertPtrEquals(tc, b, inside_building(u)); u = test_create_unit(u->faction, u->region); u->building = b; - CuAssertPtrEquals(tc, 0, inside_building(u)); + CuAssertPtrEquals(tc, NULL, inside_building(u)); b->size = 3; CuAssertPtrEquals(tc, b, inside_building(u)); test_teardown(); @@ -397,14 +397,13 @@ static void test_unit_description(CuTest *tc) { rc = test_create_race("hodor"); u = test_create_unit(test_create_faction(rc), test_create_region(0, 0, NULL)); - CuAssertPtrEquals(tc, 0, u->display); - CuAssertStrEquals(tc, 0, u_description(u, lang)); - u->display = str_strdup("Hodor"); + CuAssertStrEquals(tc, NULL, unit_getinfo(u)); + CuAssertStrEquals(tc, NULL, u_description(u, lang)); + unit_setinfo(u, "Hodor"); CuAssertStrEquals(tc, "Hodor", u_description(u, NULL)); CuAssertStrEquals(tc, "Hodor", u_description(u, lang)); - free(u->display); - u->display = NULL; + unit_setinfo(u, NULL); locale_setstring(lang, "describe_hodor", "HODOR"); CuAssertStrEquals(tc, "HODOR", u_description(u, lang)); @@ -428,37 +427,37 @@ static void test_remove_unit(CuTest *tc) { CuAssertPtrEquals(tc, u1, f->units); CuAssertPtrEquals(tc, u2, u1->nextF); CuAssertPtrEquals(tc, u1, u2->prevF); - CuAssertPtrEquals(tc, 0, u2->nextF); + CuAssertPtrEquals(tc, NULL, u2->nextF); uno = u1->no; region_setresource(r, rtype, 0); i_change(&u1->items, rtype->itype, 100); remove_unit(&r->units, u1); CuAssertIntEquals(tc, 0, u1->number); - CuAssertPtrEquals(tc, 0, u1->region); + CuAssertPtrEquals(tc, NULL, u1->region); /* money is given to a survivor: */ - CuAssertPtrEquals(tc, 0, u1->items); + CuAssertPtrEquals(tc, NULL, u1->items); CuAssertIntEquals(tc, 0, region_getresource(r, rtype)); CuAssertIntEquals(tc, 100, i_get(u2->items, rtype->itype)); /* unit is removed from f->units: */ - CuAssertPtrEquals(tc, 0, u1->nextF); + CuAssertPtrEquals(tc, NULL, u1->nextF); CuAssertPtrEquals(tc, u2, f->units); - CuAssertPtrEquals(tc, 0, u2->nextF); - CuAssertPtrEquals(tc, 0, u2->prevF); + CuAssertPtrEquals(tc, NULL, u2->nextF); + CuAssertPtrEquals(tc, NULL, u2->prevF); /* unit is no longer in r->units: */ CuAssertPtrEquals(tc, u2, r->units); - CuAssertPtrEquals(tc, 0, u2->next); + CuAssertPtrEquals(tc, NULL, u2->next); /* unit is in deleted_units: */ - CuAssertPtrEquals(tc, 0, findunit(uno)); + CuAssertPtrEquals(tc, NULL, findunit(uno)); CuAssertPtrEquals(tc, f, dfindhash(uno)); remove_unit(&r->units, u2); /* no survivor, give money to peasants: */ CuAssertIntEquals(tc, 100, region_getresource(r, rtype)); /* there are now no more units: */ - CuAssertPtrEquals(tc, 0, r->units); - CuAssertPtrEquals(tc, 0, f->units); + CuAssertPtrEquals(tc, NULL, r->units); + CuAssertPtrEquals(tc, NULL, f->units); test_teardown(); } diff --git a/src/laws.c b/src/laws.c index 68f2894b3..feacca8a1 100644 --- a/src/laws.c +++ b/src/laws.c @@ -28,8 +28,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "alchemy.h" #include "automate.h" #include "battle.h" +#include "contact.h" #include "economy.h" -#include "keyword.h" #include "market.h" #include "morale.h" #include "monsters.h" @@ -71,15 +71,17 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "kernel/unit.h" /* util includes */ -#include +#include #include -#include +#include #include +#include "util/keyword.h" #include #include #include #include #include +#include #include #include #include @@ -127,7 +129,17 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #define DMRISE 0.1F /* weekly chance that demand goes up */ #define DMRISEHAFEN 0.2F /* weekly chance that demand goes up with harbor */ -/* - exported global symbols ----------------------------------- */ +param_t findparam_ex(const char *s, const struct locale * lang) +{ + param_t result = findparam(s, lang); + + if (result == NOPARAM) { + const building_type *btype = findbuildingtype(s, lang); + if (btype != NULL) + return P_GEBAEUDE; + } + return (result == P_BUILDING) ? P_GEBAEUDE : result; +} int NewbieImmunity(void) { @@ -306,10 +318,15 @@ static void calculate_emigration(region * r) } } +/* Vermehrungsrate Bauern in 1/10000. +* TODO: Evt. Berechnungsfehler, reale Vermehrungsraten scheinen hoeher. */ +#define PEASANTGROWTH 10 +#define PEASANTLUCK 10 +#define PEASANTFORCE 0.75 /* Chance einer Vermehrung trotz 90% Auslastung */ static double peasant_growth_factor(void) { - return config_get_flt("rules.peasants.growth.factor", 0.0001F * PEASANTGROWTH); + return config_get_flt("rules.peasants.growth.factor", 0.0001 * (double)PEASANTGROWTH); } static double peasant_luck_factor(void) @@ -407,8 +424,10 @@ static migration *get_migrants(region * r) /* Es gibt noch keine Migration. Also eine erzeugen */ m = free_migrants; - if (!m) + if (!m) { m = calloc(1, sizeof(migration)); + if (!m) abort(); + } else { free_migrants = free_migrants->next; m->horses = 0; @@ -459,8 +478,8 @@ static void horses(region * r) } else if (maxhorses > 0) { double growth = - (RESOURCE_QUANTITY * HORSEGROWTH * 200 * (maxhorses - - horses)) / maxhorses; + (RESOURCE_QUANTITY * (HORSEGROWTH * 200.0 * ((double)maxhorses - + horses))) / (double)maxhorses; if (growth > 0) { int i; @@ -736,11 +755,13 @@ growing_herbs(region * r, const int current_season, const int last_weeks_season) * Kräuter))% sich zu vermehren. */ UNUSED_ARG(last_weeks_season); if (current_season != SEASON_WINTER) { - int i; - for (i = rherbs(r); i > 0; i--) { - if (rng_int() % 100 < (100 - rherbs(r))) - rsetherbs(r, (short)(rherbs(r) + 1)); + int i, herbs = rherbs(r); + for (i = herbs; i > 0; --i) { + if (rng_int() % 100 < (100 - herbs)) { + ++herbs; + } } + rsetherbs(r, herbs); } } @@ -782,7 +803,7 @@ void immigration(void) void nmr_warnings(void) { faction *f, *fa; -#define FRIEND (HELP_GUARD|HELP_MONEY) +#define HELP_NMR (HELP_GUARD|HELP_MONEY) for (f = factions; f; f = f->next) { if (!fval(f, FFL_NOIDLEOUT) && turn > f->lastorders) { ADDMSG(&f->msgs, msg_message("nmr_warning", "")); @@ -798,14 +819,12 @@ void nmr_warnings(void) warn = 1; } } - else if (alliedfaction(NULL, f, fa, FRIEND) - && alliedfaction(NULL, fa, f, FRIEND)) { + else if (alliedfaction(f, fa, HELP_NMR) && alliedfaction(fa, f, HELP_NMR)) { warn = 1; } if (warn) { if (msg == NULL) { - msg = - msg_message("warn_dropout", "faction turns", f, + msg = msg_message("warn_dropout", "faction turns", f, turn - f->lastorders); } add_message(&fa->msgs, msg); @@ -896,80 +915,6 @@ void demographics(void) immigration(); } -/* ------------------------------------------------------------- */ - -/* test if the unit can slip through a siege undetected. - * returns 0 if siege is successful, or 1 if the building is either - * not besieged or the unit can slip through the siege due to better stealth. - */ -static int slipthru(const region * r, const unit * u, const building * b) -{ - unit *u2; - int n, o; - - /* b ist die burg, in die man hinein oder aus der man heraus will. */ - if (b == NULL || b->besieged < b->size * SIEGEFACTOR) { - return 1; - } - - /* u wird am hinein- oder herausschluepfen gehindert, wenn STEALTH <= - * OBSERVATION +2 der belagerer u2 ist */ - n = effskill(u, SK_STEALTH, r); - - for (u2 = r->units; u2; u2 = u2->next) { - if (usiege(u2) == b) { - - if (invisible(u, u2) >= u->number) - continue; - - o = effskill(u2, SK_PERCEPTION, r); - - if (o + 2 >= n) { - return 0; /* entdeckt! */ - } - } - } - return 1; -} - -int can_contact(const region * r, const unit * u, const unit * u2) { - - /* hier geht es nur um die belagerung von burgen */ - UNUSED_ARG(r); - if (u->building == u2->building) { - return 1; - } - - /* unit u is trying to contact u2 - unasked for contact. wenn u oder u2 - * nicht in einer burg ist, oder die burg nicht belagert ist, ist - * slipthru () == 1. ansonsten ist es nur 1, wenn man die belagerer */ - - if (slipthru(u->region, u, u->building) && slipthru(u->region, u2, u2->building)) { - return 1; - } - - return (alliedunit(u, u2->faction, HELP_GIVE)); -} - -int contact_cmd(unit * u, order * ord) -{ - unit *u2; - int n; - - init_order_depr(ord); - n = read_unitid(u->faction, u->region); - u2 = findunit(n); - - if (u2 != NULL) { - if (!can_contact(u->region, u, u2)) { - cmistake(u, u->thisorder, 23, MSG_EVENT); - return -1; - } - usetcontact(u, u2); - } - return 0; -} - int leave_cmd(unit * u, struct order *ord) { region *r = u->region; @@ -989,13 +934,7 @@ int leave_cmd(unit * u, struct order *ord) return 0; } } - if (!slipthru(r, u, u->building)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "entrance_besieged", - "building", u->building)); - } - else { - leave(u, true); - } + leave(u, true); return 0; } @@ -1143,13 +1082,6 @@ int enter_building(unit * u, order * ord, int id, bool report) } return 0; } - if (!slipthru(r, u, b)) { - if (report) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "entrance_besieged", - "building", b)); - } - return 0; - } if (leave(u, 0)) { fset(u, UFL_ENTER); @@ -1303,6 +1235,7 @@ static void remove_idle_players(void) i = turn + 1; if (i < 4) i = 4; age = calloc(i, sizeof(int)); + if (!age) abort(); for (fp = &factions; *fp;) { faction *f = *fp; if (!is_monsters(f)) { @@ -1346,11 +1279,12 @@ void quit(void) int ally_cmd(unit * u, struct order *ord) { char token[128]; - ally *sf, **sfp; + struct allies **sfp; faction *f; int keyword, not_kw; const char *s; - + int sf_status; + init_order_depr(ord); f = getfaction(); @@ -1372,29 +1306,18 @@ int ally_cmd(unit * u, struct order *ord) sfp = &u->faction->allies; if (fval(u, UFL_GROUP)) { - attrib *a = a_find(u->attribs, &at_group); - if (a) - sfp = &((group *)a->data.v)->allies; + group *g = get_group(u); + if (g) { + sfp = &g->allies; + } } - for (sf = *sfp; sf; sf = sf->next) - if (sf->faction == f) - break; /* Gleich die passende raussuchen, wenn vorhanden */ not_kw = getparam(u->faction->locale); /* HELFE partei [modus] NICHT */ - if (!sf) { - if (keyword == P_NOT || not_kw == P_NOT) { - /* Wir helfen der Partei gar nicht... */ - return 0; - } - else { - sf = ally_add(sfp, f); - sf->status = 0; - } - } + sf_status = ally_get(*sfp, f); switch (keyword) { case P_NOT: - sf->status = 0; + sf_status = 0; break; case NOPARAM: @@ -1402,60 +1325,57 @@ int ally_cmd(unit * u, struct order *ord) return 0; case P_ANY: - if (not_kw == P_NOT) - sf->status = 0; - else - sf->status = HELP_ALL; + sf_status = (not_kw == P_NOT) ? 0 : HELP_ALL; break; case P_TRAVEL: - if (not_kw == P_NOT) - sf->status = sf->status & (HELP_ALL - HELP_TRAVEL); - else - sf->status = sf->status | HELP_TRAVEL; + if (not_kw == P_NOT) { + sf_status = sf_status & (HELP_ALL - HELP_TRAVEL); + } + else { + sf_status |= HELP_TRAVEL; + } break; case P_GIVE: if (not_kw == P_NOT) - sf->status = sf->status & (HELP_ALL - HELP_GIVE); + sf_status &= (HELP_ALL - HELP_GIVE); else - sf->status = sf->status | HELP_GIVE; + sf_status |= HELP_GIVE; break; case P_MONEY: if (not_kw == P_NOT) - sf->status = sf->status & (HELP_ALL - HELP_MONEY); + sf_status &= (HELP_ALL - HELP_MONEY); else - sf->status = sf->status | HELP_MONEY; + sf_status |= HELP_MONEY; break; case P_FIGHT: if (not_kw == P_NOT) - sf->status = sf->status & (HELP_ALL - HELP_FIGHT); + sf_status &= (HELP_ALL - HELP_FIGHT); else - sf->status = sf->status | HELP_FIGHT; + sf_status |= HELP_FIGHT; break; case P_FACTIONSTEALTH: if (not_kw == P_NOT) - sf->status = sf->status & (HELP_ALL - HELP_FSTEALTH); + sf_status &= (HELP_ALL - HELP_FSTEALTH); else - sf->status = sf->status | HELP_FSTEALTH; + sf_status |= HELP_FSTEALTH; break; case P_GUARD: if (not_kw == P_NOT) - sf->status = sf->status & (HELP_ALL - HELP_GUARD); + sf_status &= (HELP_ALL - HELP_GUARD); else - sf->status = sf->status | HELP_GUARD; + sf_status |= HELP_GUARD; break; } - sf->status &= HelpMask(); + sf_status &= HelpMask(); + ally_set(sfp, f, sf_status); - if (sf->status == 0) { /* Alle HELPs geloescht */ - removelist(sfp, sf); - } return 0; } @@ -1476,8 +1396,10 @@ static void init_prefixnames(void) } in = in->next; } - if (in == NULL) + if (in == NULL) { in = calloc(sizeof(local_names), 1); + if (!in) abort(); + } in->next = pnames; in->lang = lang; @@ -1515,19 +1437,16 @@ int prefix_cmd(unit * u, struct order *ord) } if (in == NULL) { init_prefixnames(); - for (in = pnames; in->lang != lang; in = in->next); + for (in = pnames; in && in->lang != lang; in = in->next); + if (!in) return 0; } init_order_depr(ord); s = gettoken(token, sizeof(token)); if (!s || !*s) { - attrib *a = NULL; - if (fval(u, UFL_GROUP)) { - a = a_find(u->attribs, &at_group); - } - if (a) { - group *g = (group *)a->data.v; + group *g = get_group(u); + if (g) { a_removeall(&g->attribs, &at_raceprefix); } else { @@ -1542,13 +1461,12 @@ int prefix_cmd(unit * u, struct order *ord) cmistake(u, ord, 299, MSG_EVENT); } else { - ap = &u->faction->attribs; - if (fval(u, UFL_GROUP)) { - attrib *a = a_find(u->attribs, &at_group); - if (a) { - group *g = (group *)a->data.v; - ap = &g->attribs; - } + group *g = get_group(u); + if (g) { + ap = &g->attribs; + } + else { + ap = &u->faction->attribs; } set_prefix(ap, race_prefixes[var.i]); } @@ -1596,7 +1514,7 @@ int display_cmd(unit * u, struct order *ord) break; case P_UNIT: - s = &u->display; + unit_setinfo(u, getstrtoken()); break; case P_PRIVAT: @@ -1908,11 +1826,8 @@ int name_cmd(struct unit *u, struct order *ord) case P_GROUP: { - attrib *a = NULL; - if (fval(u, UFL_GROUP)) - a = a_find(u->attribs, &at_group); - if (a) { - group *g = (group *)a->data.v; + group *g = get_group(u); + if (g) { s = &g->name; break; } @@ -2017,7 +1932,7 @@ int mail_cmd(unit * u, struct order *ord) } case P_FACTION: - n = getfactionid(); + n = getid(); for (u2 = r->units; u2; u2 = u2->next) { if (u2->faction->no == n && seefaction(u->faction, r, u2, 0)) { @@ -2140,12 +2055,10 @@ int banner_cmd(unit * u, struct order *ord) { const char * s; - free(u->faction->banner); init_order_depr(ord); s = getstrtoken(); - u->faction->banner = s ? str_strdup(s) : 0; - add_message(&u->faction->msgs, msg_message("changebanner", "value", - u->faction->banner)); + faction_setbanner(u->faction, s); + add_message(&u->faction->msgs, msg_message("changebanner", "value", s)); return 0; } @@ -2200,7 +2113,7 @@ int password_cmd(unit * u, struct order *ord) cmistake(u, ord, 283, MSG_EVENT); str_strlcpy(pwbuf, itoa36(rng_int()), sizeof(pwbuf)); } - faction_setpassword(u->faction, password_encode(pwbuf, PASSWORD_DEFAULT)); + faction_setpassword(u->faction, password_hash(pwbuf, PASSWORD_DEFAULT)); ADDMSG(&u->faction->msgs, msg_message("changepasswd", "value", pwbuf)); u->faction->flags |= FFL_PWMSG; @@ -2266,8 +2179,10 @@ static void display_item(unit * u, const item_type * itype) static void display_race(faction * f, const race * rc) { char buf[2048]; + sbstring sbs; - report_raceinfo(rc, f->locale, buf, sizeof(buf)); + sbs_init(&sbs, buf, sizeof(buf)); + report_raceinfo(rc, f->locale, &sbs); addmessage(0, f, buf, MSG_EVENT, ML_IMPORTANT); } @@ -2512,7 +2427,22 @@ int combatspell_cmd(unit * u, struct order *ord) } else { /* KAMPFZAUBER "" setzt diesen Kampfzauber */ - set_combatspell(u, sp, ord, level); + /* knowsspell prüft auf ist_magier, ist_spruch, kennt_spruch */ + if (!knowsspell(u->region, u, sp)) { + /* Fehler 'Spell not found' */ + cmistake(u, ord, 173, MSG_MAGIC); + } + else if (!u_hasspell(u, sp)) { + /* Diesen Zauber kennt die Einheit nicht */ + cmistake(u, ord, 169, MSG_MAGIC); + } + else if (!(sp->sptyp & ISCOMBATSPELL)) { + /* Diesen Kampfzauber gibt es nicht */ + cmistake(u, ord, 171, MSG_MAGIC); + } + else { + set_combatspell(u, sp, ord, level); + } } return 0; @@ -2934,7 +2864,7 @@ void maketemp_cmd(unit *u, order **olist) } u2 = create_unit(u->region, u->faction, 0, u->faction->race, alias, s, u); fset(u2, UFL_ISNEW); - a_add(&u2->attribs, a_new(&at_alias))->data.i = alias; + usetalias(u2, alias); sh = leftship(u); if (sh) { set_leftship(u2, sh); @@ -2965,7 +2895,7 @@ void maketemp_cmd(unit *u, order **olist) order *deford = default_order(u2->faction->locale); if (deford) { set_order(&u2->thisorder, NULL); - addlist(&u2->orders, deford); + unit_addorder(u2, deford); } } } @@ -3148,9 +3078,11 @@ void monthly_healing(void) /* hp über Maximum bauen sich ab. Wird zb durch Elixier der Macht * oder verändertes Ausdauertalent verursacht */ if (u->hp > umhp) { - u->hp -= (int)ceil((u->hp - umhp) / 2.0); - if (u->hp < umhp) + int diff = u->hp - umhp; + u->hp -= (int)ceil(diff / 2.0); + if (u->hp < umhp) { u->hp = umhp; + } continue; } @@ -3262,8 +3194,8 @@ static int faction_getmages(faction * f, unit ** results, int numresults) for (u = f->units; u; u = u->nextF) { if (u->number > 0) { - sc_mage *mage = get_mage_depr(u); - if (mage) { + struct sc_mage * mage = get_mage(u); + if (mage && mage_get_spellbook(mage)) { int level = effskill(u, SK_MAGIC, 0); if (level > maxlevel) { maxlevel = level; @@ -3322,11 +3254,12 @@ static void update_spells(void) unit *mages[MAXMAGES]; int i; int maxlevel = faction_getmages(f, mages, MAXMAGES); + struct spellbook *fsb; if (maxlevel && FactionSpells()) { spellbook * book = get_spellbook(magic_school[f->magiegebiet]); if (!f->spellbook) { - f->spellbook = create_spellbook(0); + f->spellbook = create_spellbook(NULL); } copy_spells(book, f->spellbook, maxlevel); if (maxlevel > f->max_spelllevel) { @@ -3334,13 +3267,14 @@ static void update_spells(void) pick_random_spells(f, maxlevel, common_spells, COMMONSPELLS); } } - show_new_spells(f, maxlevel, faction_get_spellbook(f)); + fsb = faction_get_spellbook(f); + show_new_spells(f, maxlevel, fsb); for (i = 0; i != MAXMAGES && mages[i]; ++i) { unit * u = mages[i]; - sc_mage *mage = get_mage_depr(u); - if (mage && mage->spellbook) { - int level = effskill(u, SK_MAGIC, 0); - show_new_spells(f, level, mage->spellbook); + spellbook *sb = unit_get_spellbook(u); + if (sb != fsb) { + int level = effskill(u, SK_MAGIC, NULL); + show_new_spells(f, level, sb); } } } @@ -3458,7 +3392,7 @@ int pay_cmd(unit * u, struct order *ord) static int reserve_i(unit * u, struct order *ord, int flags) { char token[128]; - if (u->number > 0 && (u_race(u)->ec_flags & ECF_GETITEM)) { + if (u->number > 0) { int use, count, para; const item_type *itype; const char *s; @@ -3492,7 +3426,10 @@ static int reserve_i(unit * u, struct order *ord, int flags) } int reserve_cmd(unit * u, struct order *ord) { - return reserve_i(u, ord, GET_DEFAULT); + if ((u_race(u)->ec_flags & ECF_GETITEM)) { + return reserve_i(u, ord, GET_DEFAULT); + } + return 0; } int reserve_self(unit * u, struct order *ord) { @@ -3582,6 +3519,7 @@ static processor *add_proc(int priority, const char *name, processor_t type) } proc = (processor *)malloc(sizeof(processor)); + if (!proc) abort(); proc->priority = priority; proc->type = type; proc->name = name; @@ -3799,98 +3737,6 @@ int armedmen(const unit * u, bool siege_weapons) return n; } -int siege_cmd(unit * u, order * ord) -{ - region *r = u->region; - building *b; - int d, pooled; - int bewaffnete, katapultiere = 0; - resource_type *rt_catapultammo = NULL; - resource_type *rt_catapult = NULL; - - init_order_depr(ord); - b = getbuilding(r); - - if (!b) { - cmistake(u, ord, 31, MSG_BATTLE); - return 31; - } - - if (!playerrace(u_race(u))) { - /* keine Drachen, Illusionen, Untote etc */ - cmistake(u, ord, 166, MSG_BATTLE); - return 166; - } - /* schaden durch katapulte */ - - rt_catapultammo = rt_find("catapultammo"); - rt_catapult = rt_find("catapult"); - - d = i_get(u->items, rt_catapult->itype); - if (d > u->number) d = u->number; - pooled = get_pooled(u, rt_catapultammo, GET_DEFAULT, d); - if (d > pooled) d = pooled; - if (effskill(u, SK_CATAPULT, 0) >= 1) { - katapultiere = d; - d *= effskill(u, SK_CATAPULT, 0); - } - else { - d = 0; - } - - bewaffnete = armedmen(u, true); - if (d == 0 && bewaffnete == 0) { - /* abbruch, falls unbewaffnet oder unfaehig, katapulte zu benutzen */ - cmistake(u, ord, 80, MSG_EVENT); - return 80; - } - - if (!is_guard(u)) { - /* abbruch, wenn die einheit nicht vorher die region bewacht - als - * warnung fuer alle anderen! */ - cmistake(u, ord, 81, MSG_EVENT); - return 81; - } - /* einheit und burg markieren - spart zeit beim behandeln der einheiten - * in der burg, falls die burg auch markiert ist und nicht alle - * einheiten wieder abgesucht werden muessen! */ - - usetsiege(u, b); - if (katapultiere < bewaffnete) katapultiere = bewaffnete; - b->besieged += katapultiere; - - /* definitiver schaden eingeschraenkt */ - if (d > b->size - 1) d = b->size - 1; - - /* meldung, schaden anrichten */ - if (d && !curse_active(get_curse(b->attribs, &ct_magicwalls))) { - b->size -= d; - use_pooled(u, rt_catapultammo, - GET_SLACK | GET_RESERVE | GET_POOLED_SLACK, d); - /* send message to the entire region */ - ADDMSG(&r->msgs, msg_message("siege_catapults", - "unit building destruction", u, b, d)); - } - else { - /* send message to the entire region */ - ADDMSG(&r->msgs, msg_message("siege", "unit building", u, b)); - } - return 0; -} - -void do_siege(region * r) -{ - if (fval(r->terrain, LAND_REGION)) { - unit *u; - - for (u = r->units; u; u = u->next) { - if (getkeyword(u->thisorder) == K_BESIEGE) { - siege_cmd(u, u->thisorder); - } - } - } -} - static void enter_1(region * r) { do_enter(r, 0); @@ -3974,11 +3820,6 @@ void init_processor(void) p += 10; add_proc_global(p, do_battles, "Attackieren"); - if (!keyword_disabled(K_BESIEGE)) { - p += 10; - add_proc_region(p, do_siege, "Belagern"); - } - p += 10; /* can't allow reserve before siege (weapons) */ add_proc_region(p, enter_1, "Betreten (3. Versuch)"); /* to claim a castle after a victory and to be able to DESTROY it in the same turn */ if (config_get_int("rules.reserve.twophase", 0)) { @@ -4136,33 +3977,6 @@ void turn_end(void) update_spells(); } -void update_subscriptions(void) -{ - FILE *F; - char zText[4096]; - - path_join(basepath(), "subscriptions", zText, sizeof(zText)); - F = fopen(zText, "r"); - if (F == NULL) { - log_warning(0, "could not open %s.\n", zText); - return; - } - for (;;) { - char zFaction[5]; - int subscription, fno; - faction *f; - - if (fscanf(F, "%4d %4s", &subscription, zFaction) <= 0) - break; - fno = atoi36(zFaction); - f = findfaction(fno); - if (f != NULL) { - f->subscription = subscription; - } - } - fclose(F); -} - /** determine if unit can be seen by faction * @param f -- the observiong faction * @param u -- the unit that is observed @@ -4196,7 +4010,7 @@ cansee(const faction * f, const region * r, const unit * u, int modifier) } /* simple visibility, just gotta have a viewer in the region to see 'em */ - if (leftship(u) || is_guard(u) || usiege(u) || u->building || u->ship) { + if (leftship(u) || is_guard(u) || u->building || u->ship) { return true; } @@ -4234,7 +4048,7 @@ bool cansee_unit(const unit * u, const unit * target, int modifier) else { int n, rings; - if (is_guard(target) || usiege(target) || target->building + if (is_guard(target) || target->building || target->ship) { return true; } @@ -4277,7 +4091,7 @@ cansee_durchgezogen(const faction * f, const region * r, const unit * u, else { int rings, n; - if (is_guard(u) || usiege(u) || u->building || u->ship) { + if (is_guard(u) || u->building || u->ship) { return true; } diff --git a/src/laws.h b/src/laws.h index 0b5db17c7..c30479b38 100755 --- a/src/laws.h +++ b/src/laws.h @@ -19,13 +19,14 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #ifndef H_GC_LAWS #define H_GC_LAWS -#include #include #ifdef __cplusplus extern "C" { #endif + enum param_t; + struct locale; struct unit; struct region; struct building; @@ -41,14 +42,12 @@ extern "C" { void demographics(void); void immigration(void); void update_guards(void); - void update_subscriptions(void); void deliverMail(struct faction *f, struct region *r, struct unit *u, const char *s, struct unit *receiver); bool renamed_building(const struct building * b); int rename_building(struct unit * u, struct order * ord, struct building * b, const char *name); void get_food(struct region * r); - int can_contact(const struct region *r, const struct unit *u, const struct unit *u2); int enter_building(struct unit *u, struct order *ord, int id, bool report); int enter_ship(struct unit *u, struct order *ord, int id, bool report); @@ -82,7 +81,6 @@ extern "C" { int quit_cmd(struct unit *u, struct order *ord); int name_cmd(struct unit *u, struct order *ord); int use_cmd(struct unit *u, struct order *ord); - int siege_cmd(struct unit *u, struct order *ord); int leave_cmd(struct unit *u, struct order *ord); int pay_cmd(struct unit *u, struct order *ord); int promotion_cmd(struct unit *u, struct order *ord); @@ -118,6 +116,8 @@ extern "C" { bool IsImmune(const struct faction *f); bool help_enter(struct unit *uo, struct unit *u); + enum param_t findparam_ex(const char *s, const struct locale * lang); + #ifdef __cplusplus } #endif diff --git a/src/laws.test.c b/src/laws.test.c index 99490c8c3..a2eca7ab5 100644 --- a/src/laws.test.c +++ b/src/laws.test.c @@ -20,10 +20,11 @@ #include #include -#include +#include #include #include #include +#include #include #include @@ -95,37 +96,6 @@ static void test_rename_building_twice(CuTest * tc) test_teardown(); } -static void test_contact(CuTest * tc) -{ - region *r; - unit *u1, *u2, *u3; - building *b; - building_type *btype; - ally *al; - - test_setup(); - test_create_locale(); - btype = test_create_buildingtype("castle"); - r = test_create_region(0, 0, NULL); - b = new_building(btype, r, default_locale); - u1 = test_create_unit(test_create_faction(NULL), r); - u2 = test_create_unit(test_create_faction(NULL), r); - u3 = test_create_unit(test_create_faction(NULL), r); - set_level(u3, SK_PERCEPTION, 2); - usetsiege(u3, b); - b->besieged = 1; - CuAssertIntEquals(tc, 1, can_contact(r, u1, u2)); - - u_set_building(u1, b); - CuAssertIntEquals(tc, 0, can_contact(r, u1, u2)); - al = ally_add(&u1->faction->allies, u2->faction); - al->status = HELP_ALL; - CuAssertIntEquals(tc, HELP_GIVE, can_contact(r, u1, u2)); - u_set_building(u2, b); - CuAssertIntEquals(tc, 1, can_contact(r, u1, u2)); - test_teardown(); -} - static void test_enter_building(CuTest * tc) { unit *u; @@ -217,12 +187,12 @@ static void test_display_cmd(CuTest *tc) { ord = create_order(K_DISPLAY, f->locale, "%s Hodor", LOC(f->locale, parameters[P_UNIT])); CuAssertIntEquals(tc, 0, display_cmd(u, ord)); - CuAssertStrEquals(tc, "Hodor", u->display); + CuAssertStrEquals(tc, "Hodor", unit_getinfo(u)); free_order(ord); ord = create_order(K_DISPLAY, f->locale, LOC(f->locale, parameters[P_UNIT])); CuAssertIntEquals(tc, 0, display_cmd(u, ord)); - CuAssertPtrEquals(tc, NULL, u->display); + CuAssertPtrEquals(tc, NULL, (void *)unit_getinfo(u)); free_order(ord); ord = create_order(K_DISPLAY, f->locale, "%s Hodor", LOC(f->locale, parameters[P_REGION])); @@ -251,7 +221,6 @@ static void test_rule_force_leave(CuTest *tc) { } static void test_force_leave_buildings(CuTest *tc) { - ally *al; region *r; unit *u1, *u2, *u3; building * b; @@ -274,8 +243,7 @@ static void test_force_leave_buildings(CuTest *tc) { CuAssertPtrNotNull(tc, test_find_messagetype(u3->faction->msgs, "force_leave_building")); u_set_building(u3, b); - al = ally_add(&u1->faction->allies, u3->faction); - al->status = HELP_GUARD; + ally_set(&u1->faction->allies, u3->faction, HELP_GUARD); force_leave(r, NULL); CuAssertPtrEquals_Msg(tc, "allies should not be forced to leave", b, u3->building); test_teardown(); @@ -421,6 +389,27 @@ static void test_unit_limit(CuTest * tc) test_teardown(); } +static void test_findparam_ex(CuTest *tc) +{ + struct locale *lang; + + test_setup(); + lang = test_create_locale(); + locale_setstring(lang, "temple", "TEMPEL"); + test_create_buildingtype("temple"); + + CuAssertIntEquals(tc, P_GEBAEUDE, findparam_ex("TEMPEL", lang)); + CuAssertIntEquals(tc, P_GEBAEUDE, findparam_ex( + locale_string(lang, parameters[P_BUILDING], false), lang)); + CuAssertIntEquals(tc, P_SHIP, findparam_ex( + locale_string(lang, parameters[P_SHIP], false), lang)); + CuAssertIntEquals(tc, P_FACTION, findparam_ex( + locale_string(lang, parameters[P_FACTION], false), lang)); + CuAssertIntEquals(tc, P_UNIT, findparam_ex( + locale_string(lang, parameters[P_UNIT], false), lang)); + test_teardown(); +} + static void test_maketemp(CuTest * tc) { faction *f; @@ -1284,25 +1273,25 @@ static void test_ally_cmd(CuTest *tc) { ord = create_order(K_ALLY, f->locale, "%s", itoa36(f->no)); ally_cmd(u, ord); CuAssertPtrEquals(tc, NULL, u->faction->msgs); - CuAssertIntEquals(tc, HELP_ALL, alliedfaction(0, u->faction, f, HELP_ALL)); + CuAssertIntEquals(tc, HELP_ALL, ally_get(u->faction->allies, f)); free_order(ord); ord = create_order(K_ALLY, f->locale, "%s %s", itoa36(f->no), LOC(f->locale, parameters[P_NOT])); ally_cmd(u, ord); CuAssertPtrEquals(tc, NULL, u->faction->msgs); - CuAssertIntEquals(tc, 0, alliedfaction(0, u->faction, f, HELP_ALL)); + CuAssertIntEquals(tc, 0, ally_get(u->faction->allies, f)); free_order(ord); ord = create_order(K_ALLY, f->locale, "%s %s", itoa36(f->no), LOC(f->locale, parameters[P_GUARD])); ally_cmd(u, ord); CuAssertPtrEquals(tc, NULL, u->faction->msgs); - CuAssertIntEquals(tc, HELP_GUARD, alliedfaction(0, u->faction, f, HELP_ALL)); + CuAssertIntEquals(tc, HELP_GUARD, ally_get(u->faction->allies, f)); free_order(ord); ord = create_order(K_ALLY, f->locale, "%s %s %s", itoa36(f->no), LOC(f->locale, parameters[P_GUARD]), LOC(f->locale, parameters[P_NOT])); ally_cmd(u, ord); CuAssertPtrEquals(tc, NULL, u->faction->msgs); - CuAssertIntEquals(tc, 0, alliedfaction(0, u->faction, f, HELP_ALL)); + CuAssertIntEquals(tc, 0, ally_get(u->faction->allies, f)); free_order(ord); test_teardown(); @@ -1494,6 +1483,34 @@ static void test_show_without_item(CuTest *tc) test_teardown(); } +static struct locale *setup_locale(void) { + struct locale *loc; + + loc = get_or_create_locale("de"); + locale_setstring(loc, "elvenhorse", "Elfenpferd"); + locale_setstring(loc, "elvenhorse_p", "Elfenpferde"); + locale_setstring(loc, "iteminfo::elvenhorse", "Elfenpferd Informationen"); + locale_setstring(loc, "race::elf_p", "Elfen"); + locale_setstring(loc, "race::elf", "Elf"); + locale_setstring(loc, "race::human_p", "Menschen"); + locale_setstring(loc, "race::human", "Mensch"); + locale_setstring(loc, "stat_hitpoints", "Trefferpunkte"); + locale_setstring(loc, "stat_attack", "Angriff"); + locale_setstring(loc, "stat_attacks", "Angriffe"); + locale_setstring(loc, "stat_defense", "Verteidigung"); + locale_setstring(loc, "stat_armor", "Ruestung"); + locale_setstring(loc, "stat_equipment", "Gegenstaende"); + locale_setstring(loc, "stat_pierce", "Pieks"); + locale_setstring(loc, "stat_cut", "Schnipp"); + locale_setstring(loc, "stat_bash", "Boink"); + locale_setstring(loc, "attack_magical", "magisch"); + locale_setstring(loc, "attack_standard", "normal"); + locale_setstring(loc, "attack_natural", "natuerlich"); + locale_setstring(loc, "attack_structural", "strukturell"); + init_locale(loc); + return loc; +} + static void test_show_race(CuTest *tc) { order *ord; race * rc; @@ -1506,12 +1523,7 @@ static void test_show_race(CuTest *tc) { test_create_race("human"); rc = test_create_race("elf"); - loc = get_or_create_locale("de"); - locale_setstring(loc, "race::elf_p", "Elfen"); - locale_setstring(loc, "race::elf", "Elf"); - locale_setstring(loc, "race::human_p", "Menschen"); - locale_setstring(loc, "race::human", "Mensch"); - init_locale(loc); + loc = setup_locale(); u = test_create_unit(test_create_faction(rc), test_create_region(0, 0, NULL)); u->faction->locale = loc; @@ -1547,13 +1559,7 @@ static void test_show_both(CuTest *tc) { 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); + loc = setup_locale(); CuAssertPtrNotNull(tc, finditemtype("elf", loc)); CuAssertPtrNotNull(tc, findrace("elf", loc)); @@ -1569,7 +1575,7 @@ static void test_show_both(CuTest *tc) { 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); + CuAssertTrue(tc, memcmp("Elfenpferd Informationen", msg->parameters[2].v, 4) == 0); test_clear_messages(u->faction); free_order(ord); test_teardown(); @@ -1805,6 +1811,7 @@ CuSuite *get_laws_suite(void) CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_maketemp_default_order); SUITE_ADD_TEST(suite, test_maketemp); + SUITE_ADD_TEST(suite, test_findparam_ex); SUITE_ADD_TEST(suite, test_nmr_warnings); SUITE_ADD_TEST(suite, test_ally_cmd); SUITE_ADD_TEST(suite, test_name_cmd); @@ -1845,7 +1852,6 @@ CuSuite *get_laws_suite(void) SUITE_ADD_TEST(suite, test_pay_cmd_must_be_owner); SUITE_ADD_TEST(suite, test_new_units); SUITE_ADD_TEST(suite, test_cannot_create_unit_above_limit); - SUITE_ADD_TEST(suite, test_contact); SUITE_ADD_TEST(suite, test_enter_building); SUITE_ADD_TEST(suite, test_enter_ship); SUITE_ADD_TEST(suite, test_display_cmd); diff --git a/src/lighthouse.c b/src/lighthouse.c index 4ef830cfc..c6c7b9915 100644 --- a/src/lighthouse.c +++ b/src/lighthouse.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/lighthouse.test.c b/src/lighthouse.test.c index d9accd49e..9dc6d2999 100644 --- a/src/lighthouse.test.c +++ b/src/lighthouse.test.c @@ -2,7 +2,7 @@ #include "lighthouse.h" -#include +#include #include #include #include diff --git a/src/listbox.c b/src/listbox.c index afc04b232..542ab13e8 100644 --- a/src/listbox.c +++ b/src/listbox.c @@ -13,14 +13,13 @@ #endif #include -#include #include "listbox.h" #include "gmtool_structs.h" -#include #include +#include #include #include #include @@ -29,7 +28,7 @@ void insert_selection(list_selection ** p_sel, list_selection * prev, const char *str, void *payload) { - list_selection *sel = calloc(sizeof(list_selection), 1); + list_selection *sel = (list_selection *)calloc(1, sizeof(list_selection)); sel->str = str_strdup(str); sel->data = payload; if (*p_sel) { @@ -57,7 +56,7 @@ const char *str, void *payload) list_selection **push_selection(list_selection ** p_sel, char *str, void *payload) { - list_selection *sel = calloc(sizeof(list_selection), 1); + list_selection *sel = (list_selection *)calloc(1, sizeof(list_selection)); list_selection *prev = NULL; sel->str = str; sel->data = payload; diff --git a/src/magic.c b/src/magic.c index 415746db0..ebaac3583 100644 --- a/src/magic.c +++ b/src/magic.c @@ -22,11 +22,12 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #endif #include "magic.h" -#include "skill.h" -#include "study.h" +#include "contact.h" #include "helpers.h" #include "laws.h" +#include "skill.h" #include "spells.h" +#include "study.h" #include #include @@ -62,14 +63,15 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include /* util includes */ -#include +#include #include -#include -#include +#include +#include #include #include #include #include +#include #include #include #include @@ -101,6 +103,78 @@ const char *magic_school[MAXMAGIETYP] = { "common" }; +struct combatspell { + int level; + const struct spell *sp; +}; + +typedef struct sc_mage { + magic_t magietyp; + int spellpoints; + int spchange; + int spellcount; + struct combatspell combatspells[MAXCOMBATSPELLS]; + struct spellbook *spellbook; +} sc_mage; + +int mage_get_spellpoints(const sc_mage *m) +{ + return m ? m->spellpoints : 0; +} + +int mage_change_spellpoints(sc_mage *m, int delta) +{ + if (m) { + int val = m->spellpoints + delta; + return m->spellpoints = (val >= 0) ? val : m->spellpoints; + } + return 0; +} + +magic_t mage_get_type(const sc_mage *m) +{ + return m ? m->magietyp : M_GRAY; +} + +const spell *mage_get_combatspell(const sc_mage *mage, int nr, int *level) +{ + assert(nr < MAXCOMBATSPELLS); + if (mage) { + if (level) { + *level = mage->combatspells[nr].level; + } + return mage->combatspells[nr].sp; + } + return NULL; +} + +void unit_set_magic(struct unit *u, enum magic_t mtype) +{ + sc_mage *mage = get_mage(u); + if (mage) { + mage->magietyp = mtype; + } +} + +magic_t unit_get_magic(const unit *u) +{ + return mage_get_type(get_mage(u)); +} + +void unit_add_spell(unit * u, struct spell * sp, int level) +{ + sc_mage *mage = get_mage(u); + + if (!mage) { + log_error("adding new spell %s to a previously non-magical unit %s\n", sp->sname, unitname(u)); + mage = create_mage(u, M_GRAY); + } + if (!mage->spellbook) { + mage->spellbook = create_spellbook(0); + } + spellbook_add(mage->spellbook, sp, level); +} + /** ** at_icastle ** TODO: separate castle-appearance from illusion-effects @@ -197,6 +271,23 @@ const building_type *icastle_type(const struct attrib *a) { extern int dice(int count, int value); +bool FactionSpells(void) +{ + static int config, rule; + if (config_changed(&config)) { + rule = config_get_int("rules.magic.factionlist", 0); + } + return rule != 0; +} + +int get_spell_level_mage(const spell * sp, void * cbdata) +{ + sc_mage *mage = (sc_mage *)cbdata; + spellbook *book = get_spellbook(magic_school[mage->magietyp]); + spellbook_entry *sbe = spellbook_get(book, sp); + return sbe ? sbe->level : 0; +} + /* ------------------------------------------------------------- */ /* aus dem alten System übriggebliegene Funktionen, die bei der * Umwandlung von alt nach neu gebraucht werden */ @@ -217,23 +308,6 @@ static void free_mage(variant *var) free(mage); } -bool FactionSpells(void) -{ - static int config, rule; - if (config_changed(&config)) { - rule = config_get_int("rules.magic.factionlist", 0); - } - return rule != 0; -} - -int get_spell_level_mage(const spell * sp, void * cbdata) -{ - sc_mage *mage = (sc_mage *)cbdata; - spellbook *book = get_spellbook(magic_school[mage->magietyp]); - spellbook_entry *sbe = spellbook_get(book, sp); - return sbe ? sbe->level : 0; -} - static int read_mage(variant *var, void *owner, struct gamedata *data) { storage *store = data->store; @@ -276,7 +350,7 @@ static int read_mage(variant *var, void *owner, struct gamedata *data) read_spellbook(&mage->spellbook, data, get_spell_level_mage, mage); } else { - read_spellbook(0, data, 0, mage); + read_spellbook(NULL, data, NULL, mage); } return AT_READ_OK; } @@ -310,9 +384,10 @@ attrib_type at_mage = { ATF_UNIQUE }; -bool is_mage(const unit * u) +bool is_mage(const struct unit * u) { - return get_mage_depr(u) != NULL; + sc_mage *m = get_mage(u); + return (m && m->magietyp != M_GRAY); } sc_mage *get_mage(const unit * u) @@ -324,12 +399,22 @@ sc_mage *get_mage(const unit * u) return NULL; } -sc_mage *get_mage_depr(const unit * u) +struct spellbook * mage_get_spellbook(const struct sc_mage * mage) { + if (mage) { + return mage->spellbook; + } + return NULL; +} + +struct spellbook * unit_get_spellbook(const struct unit * u) { - if (has_skill(u, SK_MAGIC)) { - attrib *a = a_find(u->attribs, &at_mage); - if (a) { - return (sc_mage *)a->data.v; + sc_mage * mage = get_mage(u); + if (mage) { + if (mage->spellbook) { + return mage->spellbook; + } + if (mage->magietyp != M_GRAY) { + return faction_get_spellbook(u->faction); } } return NULL; @@ -434,17 +519,15 @@ int u_hasspell(const unit *u, const struct spell *sp) int get_combatspelllevel(const unit * u, int nr) { - sc_mage *m = get_mage_depr(u); - - assert(nr < MAXCOMBATSPELLS); - if (m) { - int level = effskill(u, SK_MAGIC, 0); - if (level < m->combatspells[nr].level) { - return level; + int level; + if (mage_get_combatspell(get_mage(u), nr, &level) != NULL) { + int maxlevel = effskill(u, SK_MAGIC, 0); + if (level > maxlevel) { + return maxlevel; } - return m->combatspells[nr].level; + return level; } - return -1; + return 0; } /* ------------------------------------------------------------- */ @@ -452,40 +535,15 @@ int get_combatspelllevel(const unit * u, int nr) const spell *get_combatspell(const unit * u, int nr) { - sc_mage *m; - - assert(nr < MAXCOMBATSPELLS); - m = get_mage_depr(u); - if (m) { - return m->combatspells[nr].sp; - } - return NULL; + return mage_get_combatspell(get_mage(u), nr, NULL); } void set_combatspell(unit * u, spell * sp, struct order *ord, int level) { - sc_mage *mage = get_mage_depr(u); + sc_mage *mage = get_mage(u); int i = -1; assert(mage || !"trying to set a combat spell for non-mage"); - - /* knowsspell prüft auf ist_magier, ist_spruch, kennt_spruch */ - if (!knowsspell(u->region, u, sp)) { - /* Fehler 'Spell not found' */ - cmistake(u, ord, 173, MSG_MAGIC); - return; - } - if (!u_hasspell(u, sp)) { - /* Diesen Zauber kennt die Einheit nicht */ - cmistake(u, ord, 169, MSG_MAGIC); - return; - } - if (!(sp->sptyp & ISCOMBATSPELL)) { - /* Diesen Kampfzauber gibt es nicht */ - cmistake(u, ord, 171, MSG_MAGIC); - return; - } - if (sp->sptyp & PRECOMBATSPELL) i = 0; else if (sp->sptyp & COMBATSPELL) @@ -500,13 +558,12 @@ void set_combatspell(unit * u, spell * sp, struct order *ord, int level) void unset_combatspell(unit * u, spell * sp) { - sc_mage *m; int nr = 0; + sc_mage *m = get_mage(u); - m = get_mage_depr(u); - if (!m) + if (!m) { return; - + } if (!sp) { int i; for (i = 0; i < MAXCOMBATSPELLS; i++) { @@ -538,26 +595,15 @@ void unset_combatspell(unit * u, spell * sp) /* Gibt die aktuelle Anzahl der Magiepunkte der Einheit zurück */ int get_spellpoints(const unit * u) { - sc_mage *m; - - m = get_mage_depr(u); - if (!m) - return 0; - - return m->spellpoints; + return mage_get_spellpoints(get_mage(u)); } void set_spellpoints(unit * u, int sp) { - sc_mage *m; - - m = get_mage_depr(u); - if (!m) - return; - - m->spellpoints = sp; - - return; + sc_mage *m = get_mage(u); + if (m) { + m->spellpoints = sp; + } } /* @@ -565,23 +611,7 @@ void set_spellpoints(unit * u, int sp) */ int change_spellpoints(unit * u, int mp) { - sc_mage *m; - int sp; - - m = get_mage_depr(u); - if (!m) { - return 0; - } - - /* verhindere negative Magiepunkte */ - sp = m->spellpoints + mp; - if (sp > 0) { - m->spellpoints = sp; - } - else { - m->spellpoints = 0; - } - return sp; + return mage_change_spellpoints(get_mage(u), mp); } /* bietet die Möglichkeit, die maximale Anzahl der Magiepunkte mit @@ -591,11 +621,8 @@ static int get_spchange(const unit * u) { sc_mage *m; - m = get_mage_depr(u); - if (!m) - return 0; - - return m->spchange; + m = get_mage(u); + return m ? m->spchange : 0; } /* ein Magier kann normalerweise maximal Stufe^2.1/1.2+1 Magiepunkte @@ -619,7 +646,7 @@ static int use_item_aura(const region * r, const unit * u) return n; } -int max_spellpoints(const region * r, const unit * u) +int max_spellpoints(const struct unit *u, const region * r) { int sk; double n, msp = 0; @@ -627,6 +654,9 @@ int max_spellpoints(const region * r, const unit * u) double divisor = 1.2; const struct resource_type *rtype; + assert(u); + if (!r) r = u->region; + sk = effskill(u, SK_MAGIC, r); msp = rc_maxaura(u_race(u)) * (pow(sk, potenz) / divisor + 1) + get_spchange(u); @@ -641,59 +671,78 @@ int max_spellpoints(const region * r, const unit * u) return (msp > 0) ? (int)msp : 0; } +int max_spellpoints_depr(const struct region *r, const struct unit *u) +{ + return max_spellpoints(u, r); +} + int change_maxspellpoints(unit * u, int csp) { - sc_mage *m; - - m = get_mage_depr(u); + sc_mage *m = get_mage(u); if (!m) { return 0; } m->spchange += csp; - return max_spellpoints(u->region, u); + return max_spellpoints_depr(u->region, u); } /* ------------------------------------------------------------- */ /* Counter für die bereits gezauberte Anzahl Sprüche pro Runde. - * Um nur die Zahl der bereits gezauberten Sprüche zu ermitteln mit - * step = 0 aufrufen. */ int countspells(unit * u, int step) { - sc_mage *m; - int count; - - m = get_mage_depr(u); - if (!m) - return 0; - - if (step == 0) + sc_mage * m = get_mage(u); + if (m) { + int count; + if (step == 0) { + return m->spellcount; + } + count = m->spellcount + step; + m->spellcount = (count > 0) ? count : 0; return m->spellcount; - - count = m->spellcount + step; - - m->spellcount = (count > 0) ? count : 0; - return m->spellcount; + } + return 0; } -/* ------------------------------------------------------------- */ -/* Die für den Spruch benötigte Aura pro Stufe. - * Die Grundkosten pro Stufe werden hier um 2^count erhöht. Der - * Parameter count ist dabei die Anzahl der bereits gezauberten Sprüche +int spellcount(const unit *u) { + sc_mage *m = get_mage(u); + return m ? m->spellcount : 0; +} + +/** + * Die Grundkosten pro Stufe werden um 2^count erhöht. countspells(u) + * ist dabei die Anzahl der bereits gezauberten Sprüche */ -int spellcost(unit * u, const spell * sp) +int aura_multiplier(const unit * u) { + int count = spellcount(u); + return (1 << count); +} + +int spellcost(const unit * caster, const struct spell_component *spc) { - int k, aura = 0; - int count = countspells(u, 0); const resource_type *r_aura = get_resourcetype(R_AURA); - for (k = 0; sp->components && sp->components[k].type; k++) { - if (sp->components[k].type == r_aura) { - aura = sp->components[k].amount; + if (spc->type == r_aura) { + return spc->amount * aura_multiplier(caster); + } + return spc->amount; +} + +/** + * Die für den Spruch benötigte Aura pro Stufe. + */ +int auracost(const unit *caster, const spell *sp) { + const resource_type *r_aura = get_resourcetype(R_AURA); + if (sp->components) { + int k; + for (k = 0; sp->components[k].type; ++k) { + const struct spell_component *spc = sp->components + k; + if (r_aura == spc->type) { + return spc->amount * aura_multiplier(caster); + } } } - aura *= (1 << count); - return aura; + return 0; } /* ------------------------------------------------------------- */ @@ -724,17 +773,17 @@ static int spl_costtyp(const spell * sp) return costtyp; } -/* ------------------------------------------------------------- */ -/* durch Komponenten und cast_level begrenzter maximal möglicher - * Level +/** + * Durch Komponenten und cast_level begrenzter maximal möglicherLevel. + * * Da die Funktion nicht alle Komponenten durchprobiert sondern beim * ersten Fehler abbricht, muss die Fehlermeldung später mit cancast() * generiert werden. - * */ -int eff_spelllevel(unit * u, const spell * sp, int cast_level, int range) + */ +int eff_spelllevel(unit * u, unit *caster, const spell * sp, int cast_level, int range) { const resource_type *r_aura = get_resourcetype(R_AURA); - int k, maxlevel, needplevel; + int k, maxlevel; int costtyp = SPC_FIX; for (k = 0; sp->components && sp->components[k].type; k++) { @@ -742,17 +791,15 @@ int eff_spelllevel(unit * u, const spell * sp, int cast_level, int range) return 0; if (sp->components[k].amount > 0) { - /* Die Kosten für Aura sind auch von der Zahl der bereits - * gezauberten Sprüche abhängig */ + int level_cost = sp->components[k].amount * range; if (sp->components[k].type == r_aura) { - needplevel = spellcost(u, sp) * range; - } - else { - needplevel = sp->components[k].amount * range; + /* Die Kosten fuer Aura sind auch von der Zahl der bereits + * gezauberten Sprueche abhaengig */ + level_cost *= aura_multiplier(caster); } maxlevel = get_pooled(u, sp->components[k].type, GET_DEFAULT, - needplevel * cast_level) / needplevel; + level_cost * cast_level) / level_cost; /* sind die Kosten fix, so muss die Komponente nur einmal vorhanden * sein und der cast_level ändert sich nicht */ @@ -801,27 +848,20 @@ int eff_spelllevel(unit * u, const spell * sp, int cast_level, int range) * Je nach Kostenart werden dann die Komponenten noch mit cast_level * multipliziert. */ -void pay_spell(unit * u, const spell * sp, int cast_level, int range) +void pay_spell(unit * mage, const unit *caster, const spell * sp, int cast_level, int range) { - const resource_type *r_aura = get_resourcetype(R_AURA); int k; - int resuse; assert(cast_level > 0); for (k = 0; sp->components && sp->components[k].type; k++) { - if (sp->components[k].type == r_aura) { - resuse = spellcost(u, sp) * range; - } - else { - resuse = sp->components[k].amount * range; - } + const struct spell_component *spc = sp->components + k; + int resuse = spellcost(caster ? caster : mage, spc) * range; - if (sp->components[k].cost == SPC_LINEAR - || sp->components[k].cost == SPC_LEVEL) { + if (spc->cost == SPC_LINEAR || spc->cost == SPC_LEVEL) { resuse *= cast_level; } - use_pooled(u, sp->components[k].type, GET_DEFAULT, resuse); + use_pooled(mage, spc->type, GET_DEFAULT, resuse); } } @@ -849,9 +889,7 @@ bool knowsspell(const region * r, const unit * u, const spell * sp) bool cancast(unit * u, const spell * sp, int level, int range, struct order * ord) { - const resource_type *r_aura = get_resourcetype(R_AURA); int k; - int itemanz; resource *reslist = NULL; if (!knowsspell(u->region, u, sp)) { @@ -867,22 +905,18 @@ cancast(unit * u, const spell * sp, int level, int range, struct order * ord) } for (k = 0; sp->components && sp->components[k].type; ++k) { - if (sp->components[k].amount > 0) { - const resource_type *rtype = sp->components[k].type; - int itemhave; + const struct spell_component *spc = sp->components + k; + if (spc->amount > 0) { + const resource_type *rtype = spc->type; + int itemhave, itemanz; /* Die Kosten für Aura sind auch von der Zahl der bereits * gezauberten Sprüche abhängig */ - if (rtype == r_aura) { - itemanz = spellcost(u, sp) * range; - } - else { - itemanz = sp->components[k].amount * range; - } + itemanz = spellcost(u, spc) * range; /* sind die Kosten stufenabhängig, so muss itemanz noch mit dem * level multipliziert werden */ - switch (sp->components[k].cost) { + switch (spc->cost) { case SPC_LEVEL: case SPC_LINEAR: itemanz *= level; @@ -895,6 +929,7 @@ cancast(unit * u, const spell * sp, int level, int range, struct order * ord) itemhave = get_pooled(u, rtype, GET_DEFAULT, itemanz); if (itemhave < itemanz) { resource *res = malloc(sizeof(resource)); + assert(res); res->number = itemanz - itemhave; res->type = rtype; res->next = reslist; @@ -1212,7 +1247,7 @@ target_resists_magic(unit * magician, void *obj, int objtyp, int t_bonus) bool is_magic_resistant(unit * magician, unit * target, int resist_bonus) { - return (bool)target_resists_magic(magician, target, TYP_UNIT, + return target_resists_magic(magician, target, TYP_UNIT, resist_bonus); } @@ -1252,8 +1287,8 @@ bool fumble(region * r, unit * u, const spell * sp, int cast_grade) } /* CHAOSPATZERCHANCE 10 : +10% Chance zu Patzern */ - mage = get_mage_depr(u); - if (mage->magietyp == M_DRAIG) { + mage = get_mage(u); + if (mage && mage->magietyp == M_DRAIG) { fumble_chance += CHAOSPATZERCHANCE; } if (is_cursed(u->attribs, &ct_magicboost)) { @@ -1274,11 +1309,11 @@ bool fumble(region * r, unit * u, const spell * sp, int cast_grade) } /* ------------------------------------------------------------- */ -/* Dummy-Zauberpatzer, Platzhalter für speziel auf die Sprüche +/* Dummy-Zauberpatzer, Platzhalter für speziell auf die Sprüche * zugeschnittene Patzer */ static void fumble_default(castorder * co) { - unit *mage = co->magician.u; + unit *mage = co_get_magician(co); cmistake(mage, co->order, 180, MSG_MAGIC); @@ -1293,7 +1328,8 @@ static void do_fumble(castorder * co) { curse *c; region *r = co_get_region(co); - unit *u = co->magician.u; + unit *mage = co_get_magician(co); + unit *caster = co_get_caster(co); const spell *sp = co->sp; int level = co->level; int duration; @@ -1302,8 +1338,8 @@ static void do_fumble(castorder * co) static int rc_cache; fumble_f fun; - ADDMSG(&u->faction->msgs, - msg_message("patzer", "unit region spell", u, r, sp)); + ADDMSG(&mage->faction->msgs, + msg_message("patzer", "unit region spell", mage, r, sp)); switch (rng_int() % 10) { case 0: /* wenn vorhanden spezieller Patzer, ansonsten nix */ @@ -1323,22 +1359,22 @@ static void do_fumble(castorder * co) * The list of things to happen are attached to a timeout * trigger and that's added to the triggerlit of the mage gone toad. */ - trigger *trestore = trigger_changerace(u, u_race(u), u->irace); + trigger *trestore = trigger_changerace(mage, u_race(mage), mage->irace); if (chance(0.7)) { const resource_type *rtype = rt_find("toadslime"); if (rtype) { - t_add(&trestore, trigger_giveitem(u, rtype->itype, 1)); + t_add(&trestore, trigger_giveitem(mage, rtype->itype, 1)); } } duration = rng_int() % level / 2; if (duration < 2) duration = 2; - add_trigger(&u->attribs, "timer", trigger_timeout(duration, trestore)); + add_trigger(&mage->attribs, "timer", trigger_timeout(duration, trestore)); if (rc_changed(&rc_cache)) { rc_toad = get_race(RC_TOAD); } - u_setrace(u, rc_toad); - u->irace = NULL; - ADDMSG(&r->msgs, msg_message("patzer6", "unit region spell", u, r, sp)); + u_setrace(mage, rc_toad); + mage->irace = NULL; + ADDMSG(&r->msgs, msg_message("patzer6", "unit region spell", mage, r, sp)); break; } /* fall-through is intentional! */ @@ -1348,26 +1384,26 @@ static void do_fumble(castorder * co) duration = rng_int() % level / 2; if (duration < 2) duration = 2; effect = level / -2.0; - c = create_curse(u, &u->attribs, &ct_skillmod, level, + c = create_curse(mage, &mage->attribs, &ct_skillmod, level, duration, effect, 1); c->data.i = SK_MAGIC; - ADDMSG(&u->faction->msgs, msg_message("patzer2", "unit region", u, r)); + ADDMSG(&mage->faction->msgs, msg_message("patzer2", "unit region", mage, r)); break; case 3: case 4: /* Spruch schlägt fehl, alle Magiepunkte weg */ - set_spellpoints(u, 0); - ADDMSG(&u->faction->msgs, msg_message("patzer3", "unit region spell", - u, r, sp)); + set_spellpoints(mage, 0); + ADDMSG(&mage->faction->msgs, msg_message("patzer3", "unit region spell", + mage, r, sp)); break; case 5: case 6: /* Spruch gelingt, aber alle Magiepunkte weg */ co->level = cast_spell(co); - set_spellpoints(u, 0); - ADDMSG(&u->faction->msgs, msg_message("patzer4", "unit region spell", - u, r, sp)); + set_spellpoints(mage, 0); + ADDMSG(&mage->faction->msgs, msg_message("patzer4", "unit region spell", + mage, r, sp)); break; case 7: @@ -1376,9 +1412,9 @@ static void do_fumble(castorder * co) default: /* Spruch gelingt, alle nachfolgenden Sprüche werden 2^4 so teuer */ co->level = cast_spell(co); - ADDMSG(&u->faction->msgs, msg_message("patzer5", "unit region spell", - u, r, sp)); - countspells(u, 3); + ADDMSG(&mage->faction->msgs, msg_message("patzer5", "unit region spell", + mage, r, sp)); + countspells(caster, 3); } } @@ -1428,7 +1464,7 @@ void regenerate_aura(void) for (u = r->units; u; u = u->next) { if (u->number && is_mage(u)) { aura = get_spellpoints(u); - auramax = max_spellpoints(r, u); + auramax = max_spellpoints_depr(r, u); if (aura < auramax) { struct building *b = inside_building(u); const struct building_type *btype = building_is_active(b) ? b->type : NULL; @@ -1589,7 +1625,7 @@ verify_unit(region * r, unit * mage, const spell * sp, spllprm * spobj, static void verify_targets(castorder * co, int *invalid, int *resist, int *success) { - unit *mage = co->magician.u; + unit *mage = co_get_magician(co); const spell *sp = co->sp; region *target_r = co_get_region(co); spellparameter *sa = co->par; @@ -2036,6 +2072,10 @@ struct unit * co_get_caster(const struct castorder * co) { return co->_familiar ? co->_familiar : co->magician.u; } +struct unit * co_get_magician(const struct castorder * co) { + return co->magician.u; +} + struct region * co_get_region(const struct castorder * co) { return co->_rtarget; } @@ -2178,18 +2218,67 @@ void remove_familiar(unit * mage) } } -void create_newfamiliar(unit * mage, unit * fam) -{ - /* skills and spells: */ +static void equip_familiar(unit *fam) { + /* items, skills and spells: */ char eqname[64]; const race *rc = u_race(fam); - set_familiar(mage, fam); - snprintf(eqname, sizeof(eqname), "fam_%s", rc->_name); if (!equip_unit(fam, eqname)) { log_info("could not perform initialization for familiar %s.\n", rc->_name); } +} + +static int copy_spell_cb(spellbook_entry *sbe, void *udata) { + spellbook *sb = (spellbook *)udata; + spell * sp = spellref_get(&sbe->spref); + if (!spellbook_get(sb, sp)) { + spellbook_add(sb, sp, sbe->level); + } + return 0; +} + +/** + * Einmalige Reparatur von Vertrauten (Bugs 2451, 2517). + */ +void fix_fam_mage(unit *u) { + sc_mage *dmage; + unit *du = unit_create(0); + + u_setrace(du, u_race(u)); + dmage = create_mage(du, M_GRAY); + equip_familiar(du); + if (dmage) { + sc_mage *mage = get_mage(u); + if (!mage) { + mage = create_mage(u, dmage->magietyp); + } + else if (dmage->magietyp != mage->magietyp) { + mage->magietyp = dmage->magietyp; + } + if (dmage->spellbook) { + if (!mage->spellbook) { + mage->spellbook = create_spellbook(NULL); + spellbook_foreach(dmage->spellbook, copy_spell_cb, mage->spellbook); + } + } + else { + if (mage->spellbook) { + spellbook_clear(mage->spellbook); + mage->spellbook = NULL; + } + } + } + free_unit(du); +} + +void create_newfamiliar(unit * mage, unit * fam) +{ + + create_mage(fam, M_GRAY); + set_familiar(mage, fam); + equip_familiar(fam); + /* TODO: Diese Attribute beim Tod des Familiars entfernen: */ /* Wenn der Magier stirbt, dann auch der Vertraute */ add_trigger(&mage->attribs, "destroy", trigger_killunit(fam)); @@ -2430,7 +2519,7 @@ static castorder *cast_cmd(unit * u, order * ord) spell *sp = 0; plane *pl; spellparameter *args = NULL; - unit * caster = u; + unit * mage = u; param_t param; if (LongHunger(u)) { @@ -2500,15 +2589,15 @@ static castorder *cast_cmd(unit * u, order * ord) * können. unit_getspell findet aber nur jene Sprüche, die * die Einheit beherrscht. */ if (!sp && is_familiar(u)) { - caster = get_familiar_mage(u); - if (caster) { + mage = get_familiar_mage(u); + if (mage) { familiar = u; - sp = unit_getspell(caster, s, caster->faction->locale); + sp = unit_getspell(mage, s, mage->faction->locale); } else { /* somehow, this familiar has no mage! */ log_error("cast_cmd: familiar %s is without a mage?\n", unitname(u)); - caster = u; + mage = u; } } @@ -2595,24 +2684,22 @@ static castorder *cast_cmd(unit * u, order * ord) cmistake(u, ord, 177, MSG_MAGIC); return 0; } - if (caster != familiar) { /* Magier zaubert durch Vertrauten */ + if (mage != familiar) { /* Magier zaubert durch Vertrauten */ int sk; if (range > 1) { /* Fehler! Versucht zu Farcasten */ ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "familiar_farcast", - "mage", caster)); + "mage", mage)); return 0; } - sk = effskill(caster, SK_MAGIC, 0); - if (distance(caster->region, r) > sk) { + sk = effskill(mage, SK_MAGIC, 0); + if (distance(mage->region, r) > sk) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "familiar_toofar", - "mage", caster)); + "mage", mage)); return 0; } /* mage auf magier setzen, level anpassen, range für Erhöhung - * der Spruchkosten nutzen, langen Befehl des Magiers - * löschen, zaubern kann er noch */ + * der Spruchkosten nutzen */ range *= 2; - set_order(&caster->thisorder, NULL); sk /= 2; if (level > sk) level = sk; } @@ -2633,7 +2720,7 @@ static castorder *cast_cmd(unit * u, order * ord) unitname(u), MAX_PARAMETERS, sp->sname); } args = - add_spellparameter(target_r, caster, sp->parameter, + add_spellparameter(target_r, mage, sp->parameter, (const char *const *)params, p, ord); for (i = 0; i != p; ++i) { free(params[i]); @@ -2643,7 +2730,7 @@ static castorder *cast_cmd(unit * u, order * ord) return 0; } } - return create_castorder(0, caster, familiar, sp, target_r, level, 0, range, ord, + return create_castorder(0, mage, familiar, sp, target_r, level, 0, range, ord, args); } @@ -2716,16 +2803,17 @@ void magic(void) order *ord = co->order; int invalid, resist, success, cast_level = co->level; bool fumbled = false; - unit *u = co->magician.u; + unit *mage = co_get_magician(co); + unit *caster = co_get_caster(co); const spell *sp = co->sp; region *target_r = co_get_region(co); /* reichen die Komponenten nicht, wird der Level reduziert. */ - co->level = eff_spelllevel(u, sp, cast_level, co->distance); + co->level = eff_spelllevel(mage, caster, sp, cast_level, co->distance); if (co->level < 1) { /* Fehlermeldung mit Komponenten generieren */ - cancast(u, sp, cast_level, co->distance, ord); + cancast(mage, sp, cast_level, co->distance, ord); continue; } @@ -2733,24 +2821,24 @@ void magic(void) /* Sprüche mit Fixkosten werden immer auf Stufe des Spruchs * gezaubert, co->level ist aber defaultmäßig Stufe des Magiers */ if (spl_costtyp(sp) != SPC_FIX) { - ADDMSG(&u->faction->msgs, msg_message("missing_components", - "unit spell level", u, sp, cast_level)); + ADDMSG(&mage->faction->msgs, msg_message("missing_components", + "unit spell level", mage, sp, cast_level)); } } /* Prüfen, ob die realen Kosten für die gewünschten Stufe bezahlt * werden können */ - if (!cancast(u, sp, co->level, co->distance, ord)) { + if (!cancast(mage, sp, co->level, co->distance, ord)) { /* die Fehlermeldung wird in cancast generiert */ continue; } - co->force = MagicPower(spellpower(target_r, u, sp, co->level, ord)); + co->force = MagicPower(spellpower(target_r, mage, sp, co->level, ord)); /* die Stärke kann durch Antimagie auf 0 sinken */ if (co->force <= 0) { co->force = 0; - ADDMSG(&u->faction->msgs, msg_message("missing_force", - "unit spell level", u, sp, co->level)); + ADDMSG(&mage->faction->msgs, msg_message("missing_force", + "unit spell level", mage, sp, co->level)); } /* Ziele auf Existenz prüfen und Magieresistenz feststellen. Wurde @@ -2770,15 +2858,15 @@ void magic(void) co->force = 0; /* zwar wurde mindestens ein Ziel gefunden, das widerstand * jedoch dem Zauber. Kosten abziehen und abbrechen. */ - ADDMSG(&u->faction->msgs, msg_message("spell_resist", - "unit region spell", u, r, sp)); + ADDMSG(&mage->faction->msgs, msg_message("spell_resist", + "unit region spell", mage, r, sp)); } } /* Auch für Patzer gibt es Erfahrung, müssen die Spruchkosten * bezahlt werden und die nachfolgenden Sprüche werden teurer */ if (co->force > 0) { - if (fumble(target_r, u, sp, co->level)) { + if (fumble(target_r, mage, sp, co->level)) { /* zuerst bezahlen, dann evt in do_fumble alle Aura verlieren */ fumbled = true; } @@ -2792,12 +2880,12 @@ void magic(void) } /* erst bezahlen, dann Kostenzähler erhöhen */ if (co->level > 0) { - pay_spell(u, sp, co->level, co->distance); + pay_spell(mage, caster, sp, co->level, co->distance); } if (fumbled) { do_fumble(co); } - countspells(u, 1); + countspells(caster, 1); } } @@ -2805,9 +2893,9 @@ void magic(void) for (r = regions; r; r = r->next) { unit *u; for (u = r->units; u; u = u->next) { - if (is_mage(u) && countspells(u, 0) > 0) { + if (is_mage(u) && spellcount(u) > 0) { produceexp(u, SK_MAGIC, u->number); - /* Spruchlistenaktualiesierung ist in Regeneration */ + /* Spruchlistenaktualisierung ist in Regeneration */ } } } @@ -2857,33 +2945,22 @@ static void select_spellbook(void **tokens, spellbook *sb, const struct locale * spell *unit_getspell(struct unit *u, const char *name, const struct locale * lang) { - void * tokens = 0; spellbook *sb; sb = unit_get_spellbook(u); if (sb) { + void * tokens = NULL; select_spellbook(&tokens, sb, lang); - } -#if 0 /* TODO: some familiars can cast spells from the mage's spellbook? */ - u = get_familiar_mage(u); - if (u) { - sb = unit_get_spellbook(u); - if (sb) { - select_spellbook(&tokens, sb, lang); - } - } -#endif - - if (tokens) { - variant token; - if (findtoken(tokens, name, &token) != E_TOK_NOMATCH) { + if (tokens) { + variant token; + if (findtoken(tokens, name, &token) != E_TOK_NOMATCH) { + freetokens(tokens); + return (spell *)token.v; + } freetokens(tokens); - return (spell *)token.v; } - freetokens(tokens); } - - return 0; + return NULL; } int cast_spell(struct castorder *co) @@ -2910,6 +2987,11 @@ int cast_spell(struct castorder *co) return fun(co); } +const char *magic_name(magic_t mtype, const struct locale *lang) +{ + return LOC(lang, mkname("school", magic_school[mtype])); +} + static critbit_tree cb_spellbooks; #define SBNAMELEN 16 diff --git a/src/magic.h b/src/magic.h index 654673245..4a184fe9e 100644 --- a/src/magic.h +++ b/src/magic.h @@ -27,18 +27,16 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif - /* ------------------------------------------------------------- */ - #define MAXCOMBATSPELLS 3 /* PRECOMBAT COMBAT POSTCOMBAT */ #define MAX_SPELLRANK 9 /* Standard-Rank 5 */ #define MAXINGREDIENT 5 /* bis zu 5 Komponenten pro Zauber */ #define CHAOSPATZERCHANCE 10 /* +10% Chance zu Patzern */ - - /* ------------------------------------------------------------- */ - #define IRONGOLEM_CRUMBLE 15 /* monatlich Chance zu zerfallen */ #define STONEGOLEM_CRUMBLE 10 /* monatlich Chance zu zerfallen */ + struct sc_mage; + struct unit; + extern const char *magic_school[MAXMAGIETYP]; extern struct attrib_type at_familiar; extern struct attrib_type at_familiarmage; @@ -99,26 +97,12 @@ extern "C" { * - Spruchliste */ - typedef struct combatspell { - int level; - const struct spell *sp; - } combatspell; - typedef struct spell_names { struct spell_names *next; const struct locale *lang; void * tokens; } spell_names; - typedef struct sc_mage { - magic_t magietyp; - int spellpoints; - int spchange; - int spellcount; - combatspell combatspells[MAXCOMBATSPELLS]; - struct spellbook *spellbook; - } sc_mage; - /* ------------------------------------------------------------- */ /* Zauberliste */ @@ -140,6 +124,7 @@ extern "C" { } castorder; struct unit * co_get_caster(const struct castorder * co); + struct unit * co_get_magician(const struct castorder * co); struct region * co_get_region(const struct castorder * co); typedef struct spell_component { @@ -216,12 +201,22 @@ extern "C" { */ /* Magier */ - sc_mage *create_mage(struct unit *u, magic_t mtyp); + struct sc_mage *create_mage(struct unit *u, magic_t mtyp); /* macht die struct unit zu einem neuen Magier: legt die struct u->mage an * und initialisiert den Magiertypus mit mtyp. */ - sc_mage *get_mage(const struct unit *u); - sc_mage *get_mage_depr(const struct unit *u); - /* gibt u->mage zurück, bei nicht-Magiern *NULL */ + struct sc_mage *get_mage(const struct unit *u); + + enum magic_t mage_get_type(const struct sc_mage *mage); + const struct spell *mage_get_combatspell(const struct sc_mage *mage, int nr, int *level); + struct spellbook * mage_get_spellbook(const struct sc_mage * mage); + int mage_get_spellpoints(const struct sc_mage *m); + int mage_change_spellpoints(struct sc_mage *m, int delta); + + enum magic_t unit_get_magic(const struct unit *u); + void unit_set_magic(struct unit *u, enum magic_t mtype); + struct spellbook * unit_get_spellbook(const struct unit * u); + void unit_add_spell(struct unit * u, struct spell * sp, int level); + bool is_mage(const struct unit *u); /* gibt true, wenn u->mage gesetzt. */ bool is_familiar(const struct unit *u); @@ -257,7 +252,8 @@ extern "C" { /* setzt die Magiepunkte auf sp */ int change_spellpoints(struct unit *u, int mp); /* verändert die Anzahl der Magiepunkte der Einheit um +mp */ - int max_spellpoints(const struct region *r, const struct unit *u); + int max_spellpoints_depr(const struct region *r, const struct unit *u); + int max_spellpoints(const struct unit *u, const struct region *r); /* gibt die aktuell maximal möglichen Magiepunkte der Einheit zurück */ int change_maxspellpoints(struct unit *u, int csp); /* verändert die maximalen Magiepunkte einer Einheit */ @@ -288,9 +284,11 @@ extern "C" { /* Prüfroutinen für Zaubern */ int countspells(struct unit *u, int step); + int spellcount(const struct unit *u); /* erhöht den Counter für Zaubersprüche um 'step' und gibt die neue * Anzahl der gezauberten Sprüche zurück. */ - int spellcost(struct unit *u, const struct spell * sp); + int auracost(const struct unit *caster, const struct spell *sp); + int spellcost(const struct unit *caster, const struct spell_component *spc); /* gibt die für diesen Spruch derzeit notwendigen Magiepunkte auf der * geringstmöglichen Stufe zurück, schon um den Faktor der bereits * zuvor gezauberten Sprüche erhöht */ @@ -298,12 +296,12 @@ extern "C" { int distance, struct order *ord); /* true, wenn Einheit alle Komponenten des Zaubers (incl. MP) für die * geringstmögliche Stufe hat und den Spruch beherrscht */ - void pay_spell(struct unit *u, const struct spell * sp, int eff_stufe, int distance); + void pay_spell(struct unit *mage, const struct unit *caster, const struct spell * sp, int eff_stufe, int distance); /* zieht die Komponenten des Zaubers aus dem Inventory der Einheit * ab. Die effektive Stufe des gezauberten Spruchs ist wichtig für * die korrekte Bestimmung der Magiepunktkosten */ - int eff_spelllevel(struct unit *u, const struct spell * sp, int cast_level, - int distance); + int eff_spelllevel(struct unit *mage, struct unit *caster, + const struct spell * sp, int cast_level, int distance); /* ermittelt die effektive Stufe des Zaubers. Dabei ist cast_level * die gewünschte maximale Stufe (im Normalfall Stufe des Magiers, * bei Farcasting Stufe*2^Entfernung) */ @@ -319,6 +317,7 @@ extern "C" { * widersteht */ extern struct spell * unit_getspell(struct unit *u, const char *s, const struct locale *lang); + const char *magic_name(magic_t mtype, const struct locale *lang); /* Sprüche in der struct region */ /* (sind in curse) */ @@ -329,7 +328,8 @@ extern "C" { void remove_familiar(struct unit *mage); void create_newfamiliar(struct unit *mage, struct unit *familiar); void create_newclone(struct unit *mage, struct unit *familiar); - struct unit *has_clone(struct unit *mage); + + void fix_fam_mage(struct unit *u); const char *spell_info(const struct spell *sp, const struct locale *lang); diff --git a/src/magic.test.c b/src/magic.test.c index 95c2d250d..577e88a37 100644 --- a/src/magic.test.c +++ b/src/magic.test.c @@ -17,7 +17,7 @@ #include #include -#include +#include #include #include @@ -45,7 +45,7 @@ void test_updatespells(CuTest * tc) CuAssertPtrNotNull(tc, book); spellbook_add(book, sp, 1); - CuAssertPtrEquals(tc, 0, f->spellbook); + CuAssertPtrEquals(tc, NULL, f->spellbook); pick_random_spells(f, 1, book, 1); CuAssertPtrNotNull(tc, f->spellbook); CuAssertIntEquals(tc, 1, selist_length(f->spellbook->spells)); @@ -117,15 +117,15 @@ void test_pay_spell(CuTest * tc) CuAssertPtrNotNull(tc, sp); set_level(u, SK_MAGIC, 5); - unit_add_spell(u, 0, sp, 1); + unit_add_spell(u, sp, 1); change_resource(u, get_resourcetype(R_SILVER), 1); change_resource(u, get_resourcetype(R_AURA), 3); change_resource(u, get_resourcetype(R_HORSE), 3); - level = eff_spelllevel(u, sp, 3, 1); + level = eff_spelllevel(u, u, sp, 3, 1); CuAssertIntEquals(tc, 3, level); - pay_spell(u, sp, level, 1); + pay_spell(u, NULL, sp, level, 1); CuAssertIntEquals(tc, 0, get_resource(u, get_resourcetype(R_SILVER))); CuAssertIntEquals(tc, 0, get_resource(u, get_resourcetype(R_AURA))); CuAssertIntEquals(tc, 0, get_resource(u, get_resourcetype(R_HORSE))); @@ -151,22 +151,22 @@ void test_pay_spell_failure(CuTest * tc) CuAssertPtrNotNull(tc, sp); set_level(u, SK_MAGIC, 5); - unit_add_spell(u, 0, sp, 1); + unit_add_spell(u, sp, 1); CuAssertIntEquals(tc, 1, change_resource(u, get_resourcetype(R_SILVER), 1)); CuAssertIntEquals(tc, 2, change_resource(u, get_resourcetype(R_AURA), 2)); CuAssertIntEquals(tc, 3, change_resource(u, get_resourcetype(R_HORSE), 3)); - level = eff_spelllevel(u, sp, 3, 1); + level = eff_spelllevel(u, u, sp, 3, 1); CuAssertIntEquals(tc, 2, level); - pay_spell(u, sp, level, 1); + pay_spell(u, NULL, sp, level, 1); CuAssertIntEquals(tc, 1, change_resource(u, get_resourcetype(R_SILVER), 1)); CuAssertIntEquals(tc, 3, change_resource(u, get_resourcetype(R_AURA), 3)); CuAssertIntEquals(tc, 2, change_resource(u, get_resourcetype(R_HORSE), 1)); - CuAssertIntEquals(tc, 0, eff_spelllevel(u, sp, 3, 1)); + CuAssertIntEquals(tc, 0, eff_spelllevel(u, u, sp, 3, 1)); CuAssertIntEquals(tc, 0, change_resource(u, get_resourcetype(R_SILVER), -1)); - CuAssertIntEquals(tc, 0, eff_spelllevel(u, sp, 2, 1)); + CuAssertIntEquals(tc, 0, eff_spelllevel(u, u, sp, 2, 1)); test_teardown(); } @@ -182,7 +182,7 @@ void test_getspell_unit(CuTest * tc) r = test_create_region(0, 0, NULL); f = test_create_faction(NULL); u = test_create_unit(f, r); - create_mage(u, M_GRAY); + create_mage(u, M_GWYRRD); enable_skill(SK_MAGIC, true); set_level(u, SK_MAGIC, 1); @@ -191,9 +191,9 @@ void test_getspell_unit(CuTest * tc) sp = create_spell("testspell"); locale_setstring(lang, mkname("spell", sp->sname), "Herp-a-derp"); - CuAssertPtrEquals(tc, 0, unit_getspell(u, "Herp-a-derp", lang)); + CuAssertPtrEquals(tc, NULL, unit_getspell(u, "Herp-a-derp", lang)); - unit_add_spell(u, 0, sp, 1); + unit_add_spell(u, sp, 1); CuAssertPtrNotNull(tc, unit_getspell(u, "Herp-a-derp", lang)); test_teardown(); } @@ -220,7 +220,7 @@ void test_getspell_faction(CuTest * tc) sp = create_spell("testspell"); locale_setstring(lang, mkname("spell", sp->sname), "Herp-a-derp"); - CuAssertPtrEquals(tc, 0, unit_getspell(u, "Herp-a-derp", lang)); + CuAssertPtrEquals(tc, NULL, unit_getspell(u, "Herp-a-derp", lang)); f->spellbook = create_spellbook(0); spellbook_add(f->spellbook, sp, 1); @@ -250,7 +250,7 @@ void test_getspell_school(CuTest * tc) sp = create_spell("testspell"); locale_setstring(lang, mkname("spell", sp->sname), "Herp-a-derp"); - CuAssertPtrEquals(tc, 0, unit_getspell(u, "Herp-a-derp", lang)); + CuAssertPtrEquals(tc, NULL, unit_getspell(u, "Herp-a-derp", lang)); book = faction_get_spellbook(f); CuAssertPtrNotNull(tc, book); @@ -277,7 +277,7 @@ void test_set_pre_combatspell(CuTest * tc) sp = create_spell("testspell"); sp->sptyp |= PRECOMBATSPELL; - unit_add_spell(u, 0, sp, 1); + unit_add_spell(u, sp, 1); set_combatspell(u, sp, 0, 2); CuAssertPtrEquals(tc, sp, (spell *)get_combatspell(u, index)); @@ -287,7 +287,7 @@ void test_set_pre_combatspell(CuTest * tc) CuAssertIntEquals(tc, 1, get_combatspelllevel(u, index)); unset_combatspell(u, sp); CuAssertIntEquals(tc, 0, get_combatspelllevel(u, index)); - CuAssertPtrEquals(tc, 0, (spell *)get_combatspell(u, index)); + CuAssertPtrEquals(tc, NULL, (spell *)get_combatspell(u, index)); test_teardown(); } @@ -309,7 +309,7 @@ void test_set_main_combatspell(CuTest * tc) sp = create_spell("testspell"); sp->sptyp |= COMBATSPELL; - unit_add_spell(u, 0, sp, 1); + unit_add_spell(u, sp, 1); set_combatspell(u, sp, 0, 2); CuAssertPtrEquals(tc, sp, (spell *)get_combatspell(u, index)); @@ -319,7 +319,7 @@ void test_set_main_combatspell(CuTest * tc) CuAssertIntEquals(tc, 1, get_combatspelllevel(u, index)); unset_combatspell(u, sp); CuAssertIntEquals(tc, 0, get_combatspelllevel(u, index)); - CuAssertPtrEquals(tc, 0, (spell *)get_combatspell(u, index)); + CuAssertPtrEquals(tc, NULL, (spell *)get_combatspell(u, index)); test_teardown(); } @@ -341,7 +341,7 @@ void test_set_post_combatspell(CuTest * tc) sp = create_spell("testspell"); sp->sptyp |= POSTCOMBATSPELL; - unit_add_spell(u, 0, sp, 1); + unit_add_spell(u, sp, 1); set_combatspell(u, sp, 0, 2); CuAssertPtrEquals(tc, sp, (spell *)get_combatspell(u, index)); @@ -351,7 +351,7 @@ void test_set_post_combatspell(CuTest * tc) CuAssertIntEquals(tc, 1, get_combatspelllevel(u, index)); unset_combatspell(u, sp); CuAssertIntEquals(tc, 0, get_combatspelllevel(u, index)); - CuAssertPtrEquals(tc, 0, (spell *)get_combatspell(u, index)); + CuAssertPtrEquals(tc, NULL, (spell *)get_combatspell(u, index)); test_teardown(); } @@ -371,7 +371,7 @@ void test_hasspell(CuTest * tc) sp = create_spell("testspell"); sp->sptyp |= POSTCOMBATSPELL; - unit_add_spell(u, 0, sp, 2); + unit_add_spell(u, sp, 2); set_level(u, SK_MAGIC, 1); CuAssertTrue(tc, !u_hasspell(u, sp)); @@ -407,7 +407,7 @@ void test_multi_cast(CuTest *tc) { u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); set_level(u, SK_MAGIC, 10); - unit_add_spell(u, 0, sp, 1); + unit_add_spell(u, sp, 1); CuAssertPtrEquals(tc, sp, unit_getspell(u, "Feuerball", lang)); unit_addorder(u, create_order(K_CAST, u->faction->locale, "Feuerball")); @@ -446,19 +446,19 @@ static void test_max_spellpoints(CuTest *tc) { test_setup(); rc = test_create_race("human"); u = test_create_unit(test_create_faction(rc), test_create_region(0, 0, NULL)); - CuAssertIntEquals(tc, 1, max_spellpoints(u->region, u)); + CuAssertIntEquals(tc, 1, max_spellpoints_depr(u->region, u)); rc->maxaura = 100; - CuAssertIntEquals(tc, 1, max_spellpoints(u->region, u)); + CuAssertIntEquals(tc, 1, max_spellpoints_depr(u->region, u)); rc->maxaura = 200; - CuAssertIntEquals(tc, 2, max_spellpoints(u->region, u)); - create_mage(u, M_GRAY); + CuAssertIntEquals(tc, 2, max_spellpoints_depr(u->region, u)); + create_mage(u, M_GWYRRD); set_level(u, SK_MAGIC, 1); - CuAssertIntEquals(tc, 3, max_spellpoints(u->region, u)); + CuAssertIntEquals(tc, 3, max_spellpoints_depr(u->region, u)); set_level(u, SK_MAGIC, 2); - CuAssertIntEquals(tc, 9, max_spellpoints(u->region, u)); + CuAssertIntEquals(tc, 9, max_spellpoints_depr(u->region, u)); /* permanent aura loss: */ CuAssertIntEquals(tc, 7, change_maxspellpoints(u, -2)); - CuAssertIntEquals(tc, 7, max_spellpoints(u->region, u)); + CuAssertIntEquals(tc, 7, max_spellpoints_depr(u->region, u)); test_teardown(); } @@ -485,7 +485,7 @@ static void test_illusioncastle(CuTest *tc) static void test_is_mage(CuTest *tc) { unit *u; - sc_mage *mage; + struct sc_mage *mage; test_setup(); u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); @@ -502,18 +502,13 @@ static void test_is_mage(CuTest *tc) { static void test_get_mage(CuTest *tc) { unit *u; - sc_mage *mage; + struct sc_mage *mage; test_setup(); u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); CuAssertPtrEquals(tc, NULL, get_mage(u)); - CuAssertPtrEquals(tc, NULL, get_mage_depr(u)); CuAssertPtrNotNull(tc, mage = create_mage(u, M_CERDDOR)); CuAssertPtrEquals(tc, mage, get_mage(u)); - CuAssertPtrEquals(tc, NULL, get_mage_depr(u)); - set_level(u, SK_MAGIC, 1); - CuAssertPtrEquals(tc, mage, get_mage(u)); - CuAssertPtrEquals(tc, mage, get_mage_depr(u)); test_teardown(); } diff --git a/src/main.c b/src/main.c index e9d058b28..d51f55471 100644 --- a/src/main.c +++ b/src/main.c @@ -1,5 +1,5 @@ /* -Copyright (c) 1998-2017, Enno Rehling +Copyright (c) 1998-2018, Enno Rehling Katja Zedel @@ -22,15 +22,11 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include -#include #include -#include #include -#include #include #include -#include #include #include "eressea.h" @@ -39,14 +35,18 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #endif #include "bindings.h" -#include "races/races.h" -#include "spells.h" + +#include +#include #include -#include + +#include #include +#include +#include +#include #include -#include static const char *logfile = "eressea.log"; static const char *luafile = 0; @@ -96,6 +96,7 @@ static const char * valid_keys[] = { "game.era", "game.sender", "game.dbname", + "game.dbswap", "game.dbbatch", "editor.color", "editor.codepage", @@ -191,7 +192,7 @@ static int parse_args(int argc, char **argv) else if (argi[1] == '-') { /* long format */ if (strcmp(argi + 2, "version") == 0) { printf("Eressea version %s, " - "Copyright (C) 2017 Enno Rehling et al.\n", + "Copyright (C) 2018 Enno Rehling et al.\n", eressea_version()); return 1; #ifdef USE_CURSES @@ -302,7 +303,7 @@ void locale_init(void) } } -extern void bind_monsters(struct lua_State *L); +extern void bind_monsters(lua_State *L); int main(int argc, char **argv) { diff --git a/src/market.c b/src/market.c index 87be18f95..b954e2d35 100644 --- a/src/market.c +++ b/src/market.c @@ -16,7 +16,7 @@ without prior permission by the authors of Eressea. #include -#include +#include #include #include @@ -71,7 +71,7 @@ attrib_type at_market = { bool markets_module(void) { - return (bool)config_get_int("modules.market", 0); + return config_get_int("modules.market", 0) != 0; } void do_markets(void) diff --git a/src/modules/autoseed.c b/src/modules/autoseed.c index 374b6379c..bb31d3f4e 100644 --- a/src/modules/autoseed.c +++ b/src/modules/autoseed.c @@ -31,7 +31,7 @@ #include /* util includes */ -#include +#include #include #include #include @@ -95,7 +95,7 @@ newfaction *read_newfactions(const char *filename) faction *f; char race[20], email[64], lang[8], password[16]; newfaction *nf, **nfi; - int alliance = 0, subscription = 0; + int alliance = 0; if (fgets(buf, sizeof(buf), F) == NULL) break; @@ -103,8 +103,8 @@ newfaction *read_newfactions(const char *filename) email[0] = '\0'; password[0] = '\0'; - if (sscanf(buf, "%54s %19s %7s %15s %4d %4d", email, race, lang, - password, &subscription, &alliance) < 3) { + if (sscanf(buf, "%54s %19s %7s %15s %4d", email, race, lang, + password, &alliance) < 3) { break; } if (email[0] == '#') { @@ -133,17 +133,16 @@ newfaction *read_newfactions(const char *filename) if (nf) { continue; } - nf = calloc(sizeof(newfaction), 1); + nf = (newfaction *)calloc(1, sizeof(newfaction)); if (check_email(email) == 0) { - nf->email = str_strdup(email); + nf->email = str_strdup(email); } else { - log_error("Invalid email address for subscription %s: %s\n", itoa36(subscription), email); + log_error("Invalid email address for new faction: %s\n", email); free(nf); continue; } nf->password = str_strdup(password); nf->race = rc_find(race); - nf->subscription = subscription; if (alliances != NULL) { struct alliance *al = findalliance(alliance); if (al == NULL) { @@ -550,14 +549,16 @@ int autoseed(newfaction ** players, int nsize, int max_agediff) newfaction **nfp, *nextf = *players; faction *f; unit *u; + const char * password; isize += REGIONS_PER_FACTION; terraform_region(r, preferred_terrain(nextf->race)); prepare_starting_region(r); ++tsize; assert(r->land && r->units == 0); - u = addplayer(r, addfaction(nextf->email, nextf->password, nextf->race, - nextf->lang, nextf->subscription)); + password = nextf->password ? nextf->password : itoa36(rng_int()); + u = addplayer(r, addfaction(nextf->email, password, nextf->race, + nextf->lang)); f = u->faction; fset(f, FFL_ISNEW); f->alliance = nextf->allies; @@ -857,7 +858,7 @@ static void starting_region(newfaction ** players, region * r, region * rn[]) const struct race *rc = nf->race ? nf->race : races; const struct locale *lang = nf->lang ? nf->lang : default_locale; const char * passwd = nf->password ? nf->password : itoa36(rng_int()); - addplayer(r, addfaction(nf->email, passwd, rc, lang, 0)); + addplayer(r, addfaction(nf->email, passwd, rc, lang)); *players = nf->next; free_newfaction(nf); } diff --git a/src/modules/autoseed.h b/src/modules/autoseed.h index 937a1f8b5..b78a2df55 100644 --- a/src/modules/autoseed.h +++ b/src/modules/autoseed.h @@ -24,7 +24,6 @@ extern "C" { char *password; const struct locale *lang; const struct race *race; - int subscription; bool oldregions; struct alliance *allies; } newfaction; diff --git a/src/modules/gmcmd.c b/src/modules/gmcmd.c index 20e090114..4cc573f16 100644 --- a/src/modules/gmcmd.c +++ b/src/modules/gmcmd.c @@ -32,8 +32,8 @@ #include /* util includes */ -#include -#include +#include +#include #include #include diff --git a/src/modules/museum.c b/src/modules/museum.c index 67ce12bd1..7e3a04f2d 100644 --- a/src/modules/museum.c +++ b/src/modules/museum.c @@ -38,10 +38,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include /* util includes */ -#include +#include #include #include -#include +#include #include #include #include diff --git a/src/modules/xmas.c b/src/modules/xmas.c index b76f14eab..a8b87026a 100644 --- a/src/modules/xmas.c +++ b/src/modules/xmas.c @@ -25,10 +25,10 @@ #include /* util includes */ -#include +#include #include -#include -#include +#include +#include #include #include @@ -50,7 +50,7 @@ static void xmasgate_write(const trigger * t, struct storage *store) static int xmasgate_read(trigger * t, struct gamedata *data) { - if (read_building_reference(data, (building **)&t->data.v, NULL) <= 0) { + if (read_building_reference(data, (building **)&t->data.v) <= 0) { return AT_READ_FAIL; } return AT_READ_OK; diff --git a/src/monsters.c b/src/monsters.c index cd59f9b23..0d383ac05 100644 --- a/src/monsters.c +++ b/src/monsters.c @@ -27,17 +27,18 @@ #include "give.h" #include "guard.h" #include "laws.h" -#include "keyword.h" #include "study.h" #include "move.h" /* kernel includes */ +#include "kernel/attrib.h" #include "kernel/build.h" #include "kernel/building.h" #include "kernel/calendar.h" #include "kernel/config.h" #include "kernel/curse.h" #include "kernel/equipment.h" +#include "kernel/event.h" #include "kernel/faction.h" #include "kernel/item.h" #include "kernel/messages.h" @@ -52,11 +53,9 @@ #include "kernel/unit.h" /* util includes */ -#include #include -#include -#include -#include +#include "util/keyword.h" +#include "util/language.h" #include #include #include @@ -203,6 +202,7 @@ void monsters_desert(struct faction *monsters) int monster_attacks(unit * monster, bool rich_only) { const race *rc_serpent = get_race(RC_SEASERPENT); + int result = -1; if (monster->status < ST_AVOID) { region *r = monster->region; unit *u2; @@ -220,15 +220,16 @@ int monster_attacks(unit * monster, bool rich_only) if (!rich_only || m > 0) { order *ord = monster_attack(monster, u2); if (ord) { - addlist(&monster->orders, ord); + result = 0; + unit_addorder(monster, ord); money += m; } } } } - return money; + return money > 0 ? money : result; } - return 0; + return result; } static order *get_money_for_dragon(region * r, unit * udragon, int wanted) @@ -249,7 +250,8 @@ static order *get_money_for_dragon(region * r, unit * udragon, int wanted) * und holt sich Silber von Einheiten, vorausgesetzt er bewacht bereits */ money = 0; if (attacks && is_guard(udragon)) { - money += monster_attacks(udragon, true); + int m = monster_attacks(udragon, true); + if (m > 0) money += m; } /* falls die einnahmen erreicht werden, bleibt das monster noch eine */ @@ -738,19 +740,12 @@ void plan_monsters(faction * f) for (r = regions; r; r = r->next) { unit *u; - bool attacking = false; - /* Tiny optimization: Monsters on land only attack randomly when - * they are guarding. If nobody is guarding this region (RF_GUARDED), - * there can't be any random attacks. - */ - if (!r->land || r->flags & RF_GUARDED) { - attacking = chance(attack_chance); - } for (u = r->units; u; u = u->next) { const race *rc = u_race(u); attrib *ta; order *long_order = NULL; + bool can_move = true; /* Ab hier nur noch Befehle f�r NPC-Einheiten. */ if (u->faction!=f) @@ -761,16 +756,19 @@ void plan_monsters(faction * f) u->flags &= ~UFL_ANON_FACTION; } - /* Befehle m�ssen jede Runde neu gegeben werden: */ - free_orders(&u->orders); if (skill_enabled(SK_PERCEPTION)) { /* Monster bekommen jede Runde ein paar Tage Wahrnehmung dazu */ produceexp(u, SK_PERCEPTION, u->number); } - if (attacking && (!r->land || is_guard(u))) { - monster_attacks(u, false); + /* Befehle m�ssen jede Runde neu gegeben werden: */ + free_orders(&u->orders); + + /* All monsters guard the region: */ + if (u->status < ST_FLEE && !monster_is_waiting(u) && r->land) { + unit_addorder(u, create_order(K_GUARD, u->faction->locale, NULL)); } + /* units with a plan to kill get ATTACK orders (even if they don't guard): */ ta = a_find(u->attribs, &at_hate); if (ta && !monster_is_waiting(u)) { @@ -778,7 +776,8 @@ void plan_monsters(faction * f) if (tu && tu->region == r) { order * ord = monster_attack(u, tu); if (ord) { - addlist(&u->orders, ord); + unit_addorder(u, ord); + can_move = false; } } else if (tu) { @@ -787,17 +786,22 @@ void plan_monsters(faction * f) allowed = allowed_fly; } long_order = plan_move_to_target(u, tu->region, 2, allowed); + can_move = false; } else a_remove(&u->attribs, ta); } - /* All monsters guard the region: */ - if (u->status < ST_FLEE && !monster_is_waiting(u) && r->land) { - addlist(&u->orders, create_order(K_GUARD, u->faction->locale, NULL)); + else if (!r->land || is_guard(u)) { + if (chance(attack_chance)) { + int m = monster_attacks(u, false); + if (m >= 0) { + can_move = false; + } + } } /* Einheiten mit Bewegungsplan kriegen ein NACH: */ - if (long_order == NULL) { + if (can_move && long_order == NULL) { ta = a_find(u->attribs, &at_targetregion); if (ta) { if (u->region == (region *)ta->data.v) { @@ -818,7 +822,7 @@ void plan_monsters(faction * f) long_order = plan_dragon(u); } else { - if (rc == get_race(RC_SEASERPENT)) { + if (can_move && rc == get_race(RC_SEASERPENT)) { long_order = create_order(K_PIRACY, f->locale, NULL); } else { @@ -841,7 +845,7 @@ void plan_monsters(faction * f) } if (long_order) { - addlist(&u->orders, long_order); + unit_addorder(u, long_order); } } } diff --git a/src/monsters.test.c b/src/monsters.test.c index 54b3f7f87..75a2cbc97 100644 --- a/src/monsters.test.c +++ b/src/monsters.test.c @@ -18,7 +18,7 @@ #include "skill.h" #include "study.h" -#include +#include #include #include #include @@ -123,7 +123,7 @@ static void test_monsters_waiting(CuTest * tc) setguard(m, true); fset(m, UFL_ISNEW); monster_attacks(m, false); - CuAssertPtrEquals(tc, 0, find_order("attack 1", m)); + CuAssertPtrEquals(tc, NULL, find_order("attack 1", m)); test_teardown(); } @@ -173,7 +173,7 @@ static void test_monsters_attack_not(CuTest * tc) plan_monsters(m->faction); - CuAssertPtrEquals(tc, 0, find_order("attack 1", m)); + CuAssertPtrEquals(tc, NULL, find_order("attack 1", m)); test_teardown(); } diff --git a/src/move.c b/src/move.c index 227277ab6..c919bc041 100644 --- a/src/move.c +++ b/src/move.c @@ -1,5 +1,5 @@ /* -Copyright (c) 1998-2014, +Copyright (c) 1998-2018, Enno Rehling Katja Zedel @@ -23,6 +23,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* kernel includes */ #include "kernel/ally.h" +#include "kernel/attrib.h" #include "kernel/build.h" #include "kernel/building.h" #include "kernel/calendar.h" @@ -30,6 +31,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "kernel/connection.h" #include "kernel/curse.h" #include "kernel/faction.h" +#include "kernel/gamedata.h" #include "kernel/item.h" #include "kernel/messages.h" #include "kernel/order.h" @@ -42,18 +44,19 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "kernel/terrainid.h" #include "kernel/unit.h" -#include "move.h" +#include "alchemy.h" +#include "contact.h" #include "guard.h" #include "laws.h" +#include "lighthouse.h" +#include "monsters.h" +#include "move.h" +#include "piracy.h" #include "reports.h" #include "study.h" #include "spy.h" -#include "alchemy.h" #include "travelthru.h" #include "vortex.h" -#include "monsters.h" -#include "lighthouse.h" -#include "piracy.h" #include #include @@ -72,13 +75,12 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* util includes */ #include -#include #include -#include #include #include #include #include +#include #include #include #include @@ -891,7 +893,7 @@ static void drifting_ships(region * r) static bool present(region * r, unit * u) { - return (bool)(u && u->region == r); + return (u && u->region == r); } static void caught_target(region * r, unit * u) @@ -1428,9 +1430,10 @@ int movement_speed(const unit * u) /* Im Astralraum sind Tyb und Ill-Magier doppelt so schnell. * Nicht kumulativ mit anderen Beschleunigungen! */ if (mp * dk <= BP_WALKING * u_race(u)->speed && is_astral(u->region)) { - sc_mage *mage = get_mage(u); - if (mage && (mage->magietyp == M_TYBIED || mage->magietyp == M_ILLAUN)) { - if (has_skill(u, SK_MAGIC)) { + struct sc_mage *mage = get_mage(u); + if (mage) { + magic_t mtype = mage_get_type(mage); + if (mtype == M_TYBIED || mtype == M_ILLAUN) { mp *= 2; } } @@ -2265,7 +2268,7 @@ int follow_ship(unit * u, order * ord) return 0; } - id = getshipid(); + id = getid(); if (id <= 0) { cmistake(u, ord, 20, MSG_MOVE); @@ -2361,7 +2364,7 @@ static void move_hunters(void) break; } - if (!fval(u, UFL_LONGACTION) && !LongHunger(u) && follow_ship(u, ord)) { + if (!LongHunger(u) && follow_ship(u, ord)) { up = &r->units; break; } @@ -2549,7 +2552,7 @@ void follow_unit(unit * u) } } else if (p == P_SHIP) { - id = getshipid(); + id = getid(); if (id <= 0) { /* cmistake(u, ord, 20, MSG_MOVE); */ } @@ -2626,9 +2629,9 @@ void follow_unit(unit * u) } } if (follow) { - fset(u, UFL_FOLLOWING); fset(u2, UFL_FOLLOWED); /* FOLLOW unit on a (potentially) moving unit prevents long orders */ + fset(u, UFL_FOLLOWING | UFL_LONGACTION); set_order(&u->thisorder, NULL); } } diff --git a/src/move.test.c b/src/move.test.c index f01915e2a..40a6d3504 100644 --- a/src/move.test.c +++ b/src/move.test.c @@ -2,12 +2,13 @@ #include #include "move.h" -#include "keyword.h" +#include "contact.h" #include "lighthouse.h" -#include +#include #include #include +#include #include #include #include @@ -17,7 +18,7 @@ #include #include -#include +#include "util/keyword.h" #include #include #include @@ -129,7 +130,7 @@ static void test_ship_has_harbormaster_contact(CuTest * tc) { u = test_create_unit(test_create_faction(NULL), mf.r); u->building = mf.b; building_set_owner(u); - usetcontact(mf.b->_owner, mf.sh->_owner); + contact_unit(mf.b->_owner, mf.sh->_owner); CuAssertIntEquals(tc, SA_HARBOUR, check_ship_allowed(mf.sh, mf.r)); test_teardown(); @@ -153,7 +154,6 @@ static void test_ship_has_harbormaster_same_faction(CuTest * tc) { static void test_ship_has_harbormaster_ally(CuTest * tc) { unit *u; move_fixture mf; - ally *al; test_setup(); setup_harbor(&mf); @@ -161,8 +161,7 @@ static void test_ship_has_harbormaster_ally(CuTest * tc) { u = test_create_unit(test_create_faction(NULL), mf.r); u->building = mf.b; building_set_owner(u); - al = ally_add(&u->faction->allies, mf.u->faction); - al->status = HELP_GUARD; + ally_set(&u->faction->allies, mf.u->faction, HELP_GUARD); CuAssertIntEquals(tc, SA_HARBOUR, check_ship_allowed(mf.sh, mf.r)); test_teardown(); @@ -225,16 +224,16 @@ static void test_ship_trails(CuTest *tc) { move_ship(sh, r1, r3, NULL); CuAssertPtrEquals(tc, r3, sh->region); CuAssertPtrEquals(tc, sh, r3->ships); - CuAssertPtrEquals(tc, 0, r1->ships); - CuAssertPtrEquals(tc, 0, a_find(r1->attribs, &at_shiptrail)); - CuAssertPtrEquals(tc, 0, a_find(r3->attribs, &at_shiptrail)); + CuAssertPtrEquals(tc, NULL, r1->ships); + CuAssertPtrEquals(tc, NULL, a_find(r1->attribs, &at_shiptrail)); + CuAssertPtrEquals(tc, NULL, a_find(r3->attribs, &at_shiptrail)); add_regionlist(&route, r3); add_regionlist(&route, r2); move_ship(sh, r3, r1, route); CuAssertPtrEquals(tc, r1, sh->region); CuAssertPtrEquals(tc, sh, r1->ships); - CuAssertPtrEquals(tc, 0, r3->ships); - CuAssertPtrEquals(tc, 0, a_find(r1->attribs, &at_shiptrail)); + CuAssertPtrEquals(tc, NULL, r3->ships); + CuAssertPtrEquals(tc, NULL, a_find(r1->attribs, &at_shiptrail)); CuAssertPtrNotNull(tc, a_find(r2->attribs, &at_shiptrail)); CuAssertPtrNotNull(tc, a_find(r3->attribs, &at_shiptrail)); free_regionlist(route); @@ -258,7 +257,7 @@ static void test_age_trails(CuTest *tc) { a_age(&r1->attribs, r1); CuAssertPtrNotNull(tc, r1->attribs); a_age(&r1->attribs, r1); - CuAssertPtrEquals(tc, 0, r1->attribs); + CuAssertPtrEquals(tc, NULL, r1->attribs); free_regionlist(route); test_teardown(); } @@ -323,7 +322,7 @@ static void test_ship_empty(CuTest *tc) { movement(); CuAssertPtrEquals(tc, fix.sh->region, findregion(0, 0)); CuAssertIntEquals(tc, 2, ship_damage_percent(fix.sh)); - CuAssertPtrEquals(tc, 0, test_find_messagetype(fix.f->msgs, "ship_drift")); + CuAssertPtrEquals(tc, NULL, test_find_messagetype(fix.f->msgs, "ship_drift")); test_teardown(); } @@ -340,7 +339,7 @@ static void test_no_drift_damage(CuTest *tc) { movement(); CuAssertPtrEquals(tc, fix.sh->region, findregion(0, 0)); CuAssertIntEquals(tc, 0, ship_damage_percent(fix.sh)); - CuAssertPtrEquals(tc, 0, test_find_messagetype(fix.f->msgs, "ship_drift")); + CuAssertPtrEquals(tc, NULL, test_find_messagetype(fix.f->msgs, "ship_drift")); test_teardown(); } @@ -386,7 +385,7 @@ static void test_ship_no_real_overload(CuTest *tc) { movement(); CuAssertPtrEquals(tc, fix.u->region, findregion(0, 0)); CuAssertIntEquals(tc, 82, ship_damage_percent(fix.sh)); - CuAssertPtrEquals(tc, 0, test_find_messagetype(fix.f->msgs, "massive_overload")); + CuAssertPtrEquals(tc, NULL, test_find_messagetype(fix.f->msgs, "massive_overload")); test_teardown(); } @@ -431,7 +430,7 @@ static void test_ship_ridiculous_overload_bad(CuTest *tc) { movement(); CuAssertTrue(tc, ship_damage_percent(fix.sh) > 99); CuAssertPtrNotNull(tc, test_find_messagetype(fix.f->msgs, "massive_overload")); - CuAssertPtrEquals(tc, 0, fix.sh->region); + CuAssertPtrEquals(tc, NULL, fix.sh->region); CuAssertPtrNotNull(tc, test_find_messagetype(fix.f->msgs, "shipsink")); test_teardown(); } diff --git a/src/orderfile.c b/src/orderfile.c index 9771b7e14..90b44477b 100644 --- a/src/orderfile.c +++ b/src/orderfile.c @@ -1,5 +1,4 @@ #include -#include #include "orderfile.h" #include "kernel/calendar.h" @@ -8,17 +7,46 @@ #include "kernel/order.h" #include "kernel/unit.h" -#include -#include -#include -#include -#include -#include +#include "util/base36.h" +#include "util/message.h" +#include "util/language.h" +#include "util/log.h" +#include "util/filereader.h" +#include "util/param.h" +#include "util/parser.h" +#include "util/order_parser.h" #include +#include #include #include +static void begin_orders(unit *u) { + if (u->flags & UFL_ORDERS) { + order **ordp; + /* alle wiederholbaren, langen befehle werden gesichert: */ + u->flags |= UFL_ORDERS; + u->old_orders = u->orders; + ordp = &u->old_orders; + while (*ordp) { + order *ord = *ordp; + keyword_t kwd = getkeyword(ord); + if (!is_repeated(kwd)) { + *ordp = ord->next; + ord->next = NULL; + free_order(ord); + } + else { + ordp = &ord->next; + } + } + } + else { + free_orders(&u->orders); + } + u->orders = NULL; +} + static unit *unitorders(input *in, faction *f) { int i; @@ -33,29 +61,7 @@ static unit *unitorders(input *in, faction *f) if (u && u->faction == f) { order **ordp; - if (!fval(u, UFL_ORDERS)) { - /* alle wiederholbaren, langen befehle werden gesichert: */ - fset(u, UFL_ORDERS); - u->old_orders = u->orders; - ordp = &u->old_orders; - while (*ordp) { - order *ord = *ordp; - keyword_t kwd = getkeyword(ord); - if (!is_repeated(kwd)) { - *ordp = ord->next; - ord->next = NULL; - free_order(ord); - } - else { - ordp = &ord->next; - } - } - } - else { - free_orders(&u->orders); - } - u->orders = 0; - + begin_orders(u); ordp = &u->orders; for (;;) { @@ -125,7 +131,7 @@ static faction *factionorders(void) int fid = getid(); faction *f = findfaction(fid); - if (f != NULL && !fval(f, FFL_NPC)) { + if (f != NULL && (f->flags & FFL_NPC) == 0) { char token[128]; const char *pass = gettoken(token, sizeof(token)); @@ -223,23 +229,143 @@ int read_orders(input *in) static const char * file_getbuf(void *data) { FILE *F = (FILE *)data; - return getbuf(F, ENCODING_UTF8); + return getbuf(F); } -int readorders(const char *filename) -{ - input in; - int result; - FILE *F = fopen(filename, "r"); +typedef struct parser_state { + unit *u; + faction *f; + order **next_order; +} parser_state; - if (!F) { - perror(filename); - return -1; +static void handle_faction(void *userData, int no, const char *password) { + parser_state *state = (parser_state *)userData; + faction * f = state->f = findfaction(no); + if (!f) { + log_debug("orders for unknown faction %s", itoa36(no)); } - log_info("reading orders from %s", filename); + else { + if (checkpasswd(f, password)) { + f->lastorders = turn; + } + else { + log_debug("invalid password for faction %s", itoa36(no)); + ADDMSG(&f->msgs, msg_message("wrongpasswd", "password", password)); + } + state->u = NULL; + state->next_order = NULL; + } +} + +static void handle_unit(void *userData, int no) { + parser_state *state = (parser_state *)userData; + unit * u = findunit(no); + + state->u = NULL; + if (!u) { + /* TODO: error message */ + } + else if (u->faction != state->f) { + /* TODO: error message */ + } + else { + state->u = u; + begin_orders(u); + state->next_order = &u->orders; + } +} + +static void handle_order(void *userData, const char *str) { + parser_state *state = (parser_state *)userData; + const char * tok, *input = str; + char buffer[16]; + const struct locale *lang; + param_t p; + faction * f = state->f; + + lang = f ? f->locale : default_locale; + tok = parse_token(&input, buffer, sizeof(buffer)); + p = findparam(tok, lang); + if (p == P_FACTION || p == P_GAMENAME) { + tok = parse_token(&input, buffer, sizeof(buffer)); + if (tok) { + int no = atoi36(tok); + tok = parse_token(&input, buffer, sizeof(buffer)); + handle_faction(userData, no, tok); + } + else { + /* TODO: log_error() */ + } + } + else if (p == P_UNIT) { + tok = parse_token(&input, buffer, sizeof(buffer)); + if (tok) { + int no = atoi36(tok); + handle_unit(userData, no); + } + } + else if (p == P_NEXT) { + state->f = NULL; + state->u = NULL; + state->next_order = NULL; + } + else if (p == P_REGION) { + state->u = NULL; + state->next_order = NULL; + } + else if (state->u) { + unit * u = state->u; + order * ord = parse_order(str, lang); + if (ord) { + *state->next_order = ord; + state->next_order = &ord->next; + } + else { + ADDMSG(&u->faction->msgs, msg_message("parse_error", "unit command", u, str)); + } + } +} + +int parseorders(FILE *F) +{ + char buf[4096]; + int done = 0, err = 0; + OP_Parser parser; + parser_state state = { NULL, NULL }; + + parser = OP_ParserCreate(); + if (!parser) { + /* TODO: error message */ + return errno; + } + OP_SetOrderHandler(parser, handle_order); + OP_SetUserData(parser, &state); + + while (!done) { + size_t len = (int)fread(buf, 1, sizeof(buf), F); + if (ferror(F)) { + /* TODO: error message */ + err = errno; + break; + } + done = feof(F); + if (OP_Parse(parser, buf, len, done) == OP_STATUS_ERROR) { + /* TODO: error message */ + err = (int)OP_GetErrorCode(parser); + break; + } + } + OP_ParserFree(parser); + return err; +} + +int readorders(FILE *F) +{ + int result; + + input in; in.getbuf = file_getbuf; in.data = F; result = read_orders(&in); - fclose(F); return result; } diff --git a/src/orderfile.h b/src/orderfile.h index 43b86042e..f4260aa67 100644 --- a/src/orderfile.h +++ b/src/orderfile.h @@ -1,7 +1,7 @@ #ifndef H_ORDERFILE #define H_ORDERFILE -#include +#include #ifdef __cplusplus extern "C" { @@ -13,7 +13,8 @@ extern "C" { } input; int read_orders(struct input *in); - int readorders(const char *filename); + int readorders(FILE *F); + int parseorders(FILE *F); #ifdef __cplusplus } diff --git a/src/piracy.c b/src/piracy.c index 46977c3d8..b7307c070 100644 --- a/src/piracy.c +++ b/src/piracy.c @@ -2,10 +2,10 @@ #include "piracy.h" #include "direction.h" -#include "keyword.h" #include "move.h" #include +#include #include #include #include @@ -15,9 +15,9 @@ #include #include -#include #include #include +#include "util/keyword.h" #include #include #include diff --git a/src/piracy.test.c b/src/piracy.test.c index 9d2603d42..74e79103d 100644 --- a/src/piracy.test.c +++ b/src/piracy.test.c @@ -108,7 +108,7 @@ static void test_piracy_cmd(CuTest * tc) { u->thisorder = create_order(K_PIRACY, f->locale, "%s", itoa36(u2->faction->no)); piracy_cmd(u); - CuAssertPtrEquals(tc, 0, u->thisorder); + CuAssertPtrEquals(tc, NULL, u->thisorder); CuAssertTrue(tc, u->region != r); CuAssertPtrEquals(tc, u2->region, u->region); CuAssertPtrEquals(tc, u2->region, u->ship->region); @@ -213,7 +213,7 @@ static void test_piracy_cmd_land_to_land(CuTest * tc) { u->thisorder = create_order(K_PIRACY, f->locale, "%s", itoa36(target)); piracy_cmd(u); - CuAssertPtrEquals(tc, 0, u->thisorder); + CuAssertPtrEquals(tc, NULL, u->thisorder); CuAssertPtrEquals(tc, r, u->region); test_teardown(); @@ -228,7 +228,7 @@ static void test_piracy_cmd_swimmer(CuTest * tc) { r = pirate->region; piracy_cmd(pirate); - CuAssertPtrEquals(tc, 0, pirate->thisorder); + CuAssertPtrEquals(tc, NULL, pirate->thisorder); CuAssertTrue(tc, pirate->region != r); CuAssertPtrEquals(tc, victim->region, pirate->region); CuAssertPtrNotNullMsg(tc, "successful PIRACY message", test_find_messagetype(pirate->faction->msgs, "piratesawvictim")); diff --git a/src/platform.h b/src/platform.h index fb1ace65a..7b52782e3 100644 --- a/src/platform.h +++ b/src/platform.h @@ -4,8 +4,6 @@ #define _LP64 0 /* fix a warning in pdcurses 3.4 */ #endif -#ifdef _MSC_VER - /* @see https://developercommunity.visualstudio.com/content/problem/69874/warning-c4001-in-standard-library-stringh-header.html */ #if _MSC_VER >= 1900 #pragma warning(disable: 4710 4820 4001) @@ -14,11 +12,7 @@ #pragma warning(disable: 4457) // declaration hides function parameter #pragma warning(disable: 4459) // declaration hides global #pragma warning(disable: 4224) // formal parameter was previously defined as a type -#endif - -/* @see https://insanecoding.blogspot.no/2007/11/pathmax-simply-isnt.html */ -#define PATH_MAX 260 - +#pragma warning(disable: 4214) // bit field types other than int #endif #define MIN(a, b) (((a) < (b)) ? (a) : (b)) diff --git a/src/prefix.test.c b/src/prefix.test.c index f131813d7..e95f0c281 100644 --- a/src/prefix.test.c +++ b/src/prefix.test.c @@ -11,17 +11,17 @@ static void test_add_prefix(CuTest *tc) { test_setup(); - CuAssertPtrEquals(tc, 0, race_prefixes); + CuAssertPtrEquals(tc, NULL, race_prefixes); CuAssertIntEquals(tc, 0, add_raceprefix("sea")); CuAssertPtrNotNull(tc, race_prefixes); CuAssertStrEquals(tc, "sea", race_prefixes[0]); - CuAssertPtrEquals(tc, 0, race_prefixes[1]); + CuAssertPtrEquals(tc, NULL, race_prefixes[1]); CuAssertIntEquals(tc, 0, add_raceprefix("moon")); CuAssertStrEquals(tc, "sea", race_prefixes[0]); CuAssertStrEquals(tc, "moon", race_prefixes[1]); - CuAssertPtrEquals(tc, 0, race_prefixes[2]); + CuAssertPtrEquals(tc, NULL, race_prefixes[2]); free_prefixes(); - CuAssertPtrEquals(tc, 0, race_prefixes); + CuAssertPtrEquals(tc, NULL, race_prefixes); test_teardown(); } diff --git a/src/process.pkg b/src/process.pkg index a81917293..89e8f2fa7 100755 --- a/src/process.pkg +++ b/src/process.pkg @@ -21,7 +21,6 @@ module eressea { void process_movement @ movement(void); /* MOVE/FOLLOW/ROUTE */ void process_use @ use(void); /* USE */ void process_battle @ battle(void); /* ATTACK */ - void process_siege @ siege(void); /* SIEGE */ void process_leave @ leave(void); /* LEAVE */ void process_maintenance @ maintenance(void); /* PAY */ void process_promote @ promote(void); /* PROMOTE */ diff --git a/src/process.pkg.c b/src/process.pkg.c index 42dff20ff..3e818f7ce 100644 --- a/src/process.pkg.c +++ b/src/process.pkg.c @@ -435,30 +435,6 @@ static int tolua_process_eressea_process_battle00(lua_State* tolua_S) #endif } -/* function: process_siege */ -static int tolua_process_eressea_process_siege00(lua_State* tolua_S) -{ -#ifndef TOLUA_RELEASE - tolua_Error tolua_err; - if ( - !tolua_isnoobj(tolua_S,1,&tolua_err) - ) - goto tolua_lerror; - else -#endif - { - { - process_siege(); - } - } - return 0; -#ifndef TOLUA_RELEASE - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'siege'.",&tolua_err); - return 0; -#endif -} - /* function: process_leave */ static int tolua_process_eressea_process_leave00(lua_State* tolua_S) { @@ -993,7 +969,6 @@ LUALIB_API int luaopen_process (lua_State* tolua_S) tolua_function(tolua_S,"movement",tolua_process_eressea_process_movement00); tolua_function(tolua_S,"use",tolua_process_eressea_process_use00); tolua_function(tolua_S,"battle",tolua_process_eressea_process_battle00); - tolua_function(tolua_S,"siege",tolua_process_eressea_process_siege00); tolua_function(tolua_S,"leave",tolua_process_eressea_process_leave00); tolua_function(tolua_S,"maintenance",tolua_process_eressea_process_maintenance00); tolua_function(tolua_S,"promote",tolua_process_eressea_process_promote00); diff --git a/src/races/races.c b/src/races/races.c index 120a15dd9..7eede1b38 100644 --- a/src/races/races.c +++ b/src/races/races.c @@ -21,7 +21,7 @@ #include #include -#include +#include #include #include @@ -30,7 +30,6 @@ void age_firedragon(struct unit *u); void age_dragon(struct unit *u); -void age_undead(struct unit *u); void age_skeleton(struct unit *u); void age_zombie(struct unit *u); void age_ghoul(struct unit *u); @@ -81,7 +80,6 @@ void equip_newunits(struct unit *u) void register_races(void) { /* function age for race->age() */ - register_function((pf_generic)age_undead, "age_undead"); register_function((pf_generic)age_skeleton, "age_skeleton"); register_function((pf_generic)age_zombie, "age_zombie"); register_function((pf_generic)age_ghoul, "age_ghoul"); diff --git a/src/races/zombies.c b/src/races/zombies.c index de3d81972..3c880d819 100644 --- a/src/races/zombies.c +++ b/src/races/zombies.c @@ -40,29 +40,6 @@ void make_undead_unit(unit * u) u->flags |= UFL_ISNEW; } -void age_undead(unit * u) -{ - region *r = u->region; - - /* untote, die einer partei angehoeren, koennen sich - * absplitten, anstatt sich zu vermehren. monster - * untote vermehren sich nur noch */ - - if (u->number > UNDEAD_MIN && !is_monsters(u->faction) - && rng_int() % 100 < UNDEAD_BREAKUP) { - int m, n = 0; - unit *u2; - - for (m = u->number; m; m--) { - if (rng_int() % 100 < UNDEAD_BREAKUP_FRACTION) - ++n; - } - u2 = create_unit(r, get_monsters(), 0, get_race(RC_UNDEAD), 0, NULL, u); - make_undead_unit(u2); - transfermen(u, u2, u->number - n); - } -} - void age_skeleton(unit * u) { if (is_monsters(u->faction) && rng_int() % 100 < age_chance(u->age, 27, 1)) { diff --git a/src/randenc.c b/src/randenc.c index 820d3760f..79998c14b 100644 --- a/src/randenc.c +++ b/src/randenc.c @@ -56,7 +56,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "kernel/unit.h" /* util includes */ -#include "util/attrib.h" +#include "kernel/attrib.h" #include "util/language.h" #include "util/lists.h" #include "util/log.h" diff --git a/src/renumber.c b/src/renumber.c index 43a55ef83..e562a0285 100644 --- a/src/renumber.c +++ b/src/renumber.c @@ -1,6 +1,9 @@ #include #include "renumber.h" +#include "laws.h" + +#include #include #include #include @@ -9,8 +12,8 @@ #include #include -#include #include +#include #include #include diff --git a/src/renumber.test.c b/src/renumber.test.c index b67384b8f..f65011cf7 100644 --- a/src/renumber.test.c +++ b/src/renumber.test.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include diff --git a/src/report.c b/src/report.c index 9f1bfa4bd..04e5408ad 100644 --- a/src/report.c +++ b/src/report.c @@ -19,7 +19,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #ifdef _MSC_VER #include #endif -#include #include "report.h" #include "reports.h" @@ -50,8 +49,11 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "teleport.h" /* kernel includes */ +#include "kernel/alliance.h" #include "kernel/ally.h" +#include "kernel/attrib.h" #include "kernel/calendar.h" +#include "kernel/config.h" #include "kernel/connection.h" #include "kernel/build.h" #include "kernel/building.h" @@ -74,10 +76,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "kernel/terrain.h" #include "kernel/terrainid.h" #include "kernel/unit.h" -#include "kernel/alliance.h" /* util includes */ -#include #include #include "util/bsdstring.h" #include @@ -86,6 +86,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include "util/param.h" #include #include @@ -675,7 +676,7 @@ nr_unit(struct stream *out, const faction * f, const unit * u, int indent, seen_ return; newline(out); - dh = bufunit(f, u, mode, buf, sizeof(buf)); + dh = bufunit_depr(f, u, mode, buf, sizeof(buf)); if (u->faction == f) { marker = '*'; @@ -872,6 +873,8 @@ bool see_border(const connection * b, const faction * f, const region * r) return cs; } +#define MAX_EDGES 16 + void report_region(struct stream *out, const region * r, faction * f) { int n; @@ -882,13 +885,13 @@ void report_region(struct stream *out, const region * r, faction * f) attrib *a; const char *tname; struct edge { - struct edge *next; char *name; bool transparent; bool block; bool exist[MAXDIRECTIONS]; direction_t lastd; - } *edges = NULL, *e; + } edges[MAX_EDGES]; + int ne = 0; bool see[MAXDIRECTIONS]; char buf[8192]; char *bufp = buf; @@ -899,6 +902,7 @@ void report_region(struct stream *out, const region * r, faction * f) assert(f); assert(r); + memset(edges, 0, sizeof(edges)); for (d = 0; d != MAXDIRECTIONS; d++) { /* Nachbarregionen, die gesehen werden, ermitteln */ region *r2 = rconnect(r, d); @@ -907,7 +911,8 @@ void report_region(struct stream *out, const region * r, faction * f) if (!r2) continue; for (b = get_borders(r, r2); b;) { - struct edge *edg = edges; + int e; + struct edge *match = NULL; bool transparent = b->type->transparent(b, f); const char *name = border_name(b, r, f, GF_DETAILED | GF_ARTICLE); @@ -918,18 +923,22 @@ void report_region(struct stream *out, const region * r, faction * f) b = b->next; continue; } - while (edg && (edg->transparent != transparent || strcmp(name, edg->name)!=0)) { - edg = edg->next; + for (e = 0; e!=ne; ++e) { + struct edge *edg = edges + e; + if (edg->transparent == transparent && 0 == strcmp(name, edg->name)) { + match = edg; + break; + } } - if (!edg) { - edg = calloc(sizeof(struct edge), 1); - edg->name = str_strdup(name); - edg->transparent = transparent; - edg->next = edges; - edges = edg; + if (match == NULL) { + match = edges + ne; + match->name = str_strdup(name); + match->transparent = transparent; + ++ne; + assert(ne < MAX_EDGES); } - edg->lastd = d; - edg->exist[d] = true; + match->lastd = d; + match->exist[d] = true; b = b->next; } } @@ -1226,27 +1235,22 @@ void report_region(struct stream *out, const region * r, faction * f) nr_curses(out, 0, f, TYP_REGION, r); n = 0; - if (edges) + if (ne > 0) { + int e; newline(out); - for (e = edges; e; e = e->next) { - message *msg; + for (e = 0; e != ne; ++e) { + message *msg; - for (d = 0; d != MAXDIRECTIONS; ++d) { - if (e->exist[d]) { - msg = msg_message(e->transparent ? "nr_border_transparent" : "nr_border_opaque", - "object dir", e->name, d); - nr_render(msg, f->locale, buf, sizeof(buf), f); - msg_release(msg); - paragraph(out, buf, 0, 0, 0); + for (d = 0; d != MAXDIRECTIONS; ++d) { + if (edges[e].exist[d]) { + msg = msg_message(edges[e].transparent ? "nr_border_transparent" : "nr_border_opaque", + "object dir", edges[e].name, d); + nr_render(msg, f->locale, buf, sizeof(buf), f); + msg_release(msg); + paragraph(out, buf, 0, 0, 0); + } } - } - } - if (edges) { - while (edges) { - e = edges->next; - free(edges->name); - free(edges); - edges = e; + free(edges[e].name); } } } @@ -1507,97 +1511,94 @@ report_template(const char *filename, report_context * ctx, const char *bom) return 0; } -static void -show_allies(const faction * f, const ally * allies, char *buf, size_t size) -{ - int allierte = 0; - int i = 0, h, hh = 0; - int bytes, dh = 0; - const ally *sf; - char *bufp = buf; /* buf already contains data */ - - --size; /* leave room for a null-terminator */ - - for (sf = allies; sf; sf = sf->next) { - int mode = alliedgroup(NULL, f, sf->faction, sf, HELP_ALL); - if (mode > 0) - ++allierte; +static int count_allies_cb(struct allies *all, faction *af, int status, void *udata) { + int *num = (int *)udata; + if (status > 0) { + ++*num; } + return 0; +} - for (sf = allies; sf; sf = sf->next) { - int mode = alliedgroup(NULL, f, sf->faction, sf, HELP_ALL); - if (mode <= 0) - continue; - i++; - if (dh) { - if (i == allierte) { - bytes = (int)str_strlcpy(bufp, LOC(f->locale, "list_and"), size); - } - else { - bytes = (int)str_strlcpy(bufp, ", ", size); - } - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - } - dh = 1; - hh = 0; - bytes = (int)str_strlcpy(bufp, factionname(sf->faction), size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - bytes = (int)str_strlcpy(bufp, " (", size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - if ((mode & HELP_ALL) == HELP_ALL) { - bytes = (int)str_strlcpy(bufp, LOC(f->locale, parameters[P_ANY]), size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); +struct show_s { + sbstring sbs; + const faction *f; + int num_allies; +}; + +static int show_allies_cb(struct allies *all, faction *af, int status, void *udata) { + struct show_s * show = (struct show_s *)udata; + const faction * f = show->f; + + int mode = alliance_status(f, af, status); + --show->num_allies; + if (sbs_length(&show->sbs) > 0) { + /* not the first entry */ + if (0 == show->num_allies) { + sbs_strcat(&show->sbs, LOC(f->locale, "list_and")); } else { - for (h = 1; h <= HELP_TRAVEL; h *= 2) { - int p = MAXPARAMS; - if ((mode & h) == h) { - switch (h) { - case HELP_TRAVEL: - p = P_TRAVEL; - break; - case HELP_MONEY: - p = P_MONEY; - break; - case HELP_FIGHT: - p = P_FIGHT; - break; - case HELP_GIVE: - p = P_GIVE; - break; - case HELP_GUARD: - p = P_GUARD; - break; - case HELP_FSTEALTH: - p = P_FACTIONSTEALTH; - break; - } - } - if (p != MAXPARAMS) { - if (hh) { - bytes = (int)str_strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - } - bytes = (int)str_strlcpy(bufp, LOC(f->locale, parameters[p]), size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - hh = 1; + sbs_strcat(&show->sbs, ", "); + } + } + sbs_strcat(&show->sbs, factionname(af)); + sbs_strcat(&show->sbs, " ("); + if ((mode & HELP_ALL) == HELP_ALL) { + sbs_strcat(&show->sbs, LOC(f->locale, parameters[P_ANY])); + } + else { + int h, hh = 0; + for (h = 1; h <= HELP_TRAVEL; h *= 2) { + int p = MAXPARAMS; + if ((mode & h) == h) { + switch (h) { + case HELP_TRAVEL: + p = P_TRAVEL; + break; + case HELP_MONEY: + p = P_MONEY; + break; + case HELP_FIGHT: + p = P_FIGHT; + break; + case HELP_GIVE: + p = P_GIVE; + break; + case HELP_GUARD: + p = P_GUARD; + break; + case HELP_FSTEALTH: + p = P_FACTIONSTEALTH; + break; } } + if (p != MAXPARAMS) { + if (hh) { + sbs_strcat(&show->sbs, ", "); + } + sbs_strcat(&show->sbs, LOC(f->locale, parameters[p])); + hh = 1; + } } - bytes = (int)str_strlcpy(bufp, ")", size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); } - bytes = (int)str_strlcpy(bufp, ".", size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - *bufp = 0; + sbs_strcat(&show->sbs, ")"); + return 0; +} + +static void +show_allies(const faction * f, struct allies * allies, char *buf, size_t size) +{ + int num_allies = 0; + allies_walk(allies, count_allies_cb, &num_allies); + + if (num_allies > 0) { + struct show_s show; + show.f = f; + show.num_allies = num_allies; + sbs_init(&show.sbs, buf, size); + + allies_walk(allies, show_allies_cb, &show); + sbs_strcat(&show.sbs, "."); + } } static void allies(struct stream *out, const faction * f) @@ -1723,16 +1724,19 @@ static void list_address(struct stream *out, const faction * uf, selist * seenfa while (flist != NULL) { const faction *f = (const faction *)selist_get(flist, qi); if (!is_monsters(f)) { + const char *str; char buf[8192]; char label = '-'; + str = faction_getbanner(f); sprintf(buf, "%s: %s; %s", factionname(f), faction_getemail(f), - f->banner ? f->banner : ""); + str ? str : ""); if (uf == f) label = '*'; - else if (is_allied(uf, f)) + else if (is_allied(uf, f)) { label = 'o'; - else if (alliedfaction(NULL, uf, f, HELP_ALL)) + } + else if (alliedfaction(uf, f, HELP_ALL)) label = '+'; paragraph(out, buf, 4, 0, label); } @@ -1821,7 +1825,6 @@ nr_building(struct stream *out, const region *r, const building *b, const factio const char *name, *bname, *billusion = NULL; const struct locale *lang; char buffer[8192]; - message *msg; size_t size; sbstring sbs; @@ -1853,15 +1856,6 @@ nr_building(struct stream *out, const region *r, const building *b, const factio sbs_strcat(&sbs, LOC(lang, "nr_building_inprogress")); } - if (b->besieged > 0 && r->seen.mode >= seen_lighthouse) { - msg = msg_message("nr_building_besieged", "soldiers diff", b->besieged, - b->besieged - b->size * SIEGEFACTOR); - - size = nr_render(msg, lang, sbs.end, sbs.size - (sbs.end - sbs.begin), f); - sbs.end += size; - - msg_release(msg); - } i = 0; if (b->display && b->display[0]) { sbs_strcat(&sbs, "; "); @@ -1988,8 +1982,6 @@ void report_travelthru(struct stream *out, region *r, const faction *f) } } -#include "util/bsdstring.h" - int report_plaintext(const char *filename, report_context * ctx, const char *bom) @@ -2032,7 +2024,7 @@ report_plaintext(const char *filename, report_context * ctx, newline(out); sprintf(buf, "%s, %s/%s (%s)", factionname(f), LOC(f->locale, rc_name_s(f->race, NAME_PLURAL)), - LOC(f->locale, mkname("school", magic_school[f->magiegebiet])), faction_getemail(f)); + magic_name(f->magiegebiet, f->locale), faction_getemail(f)); centre(out, buf, true); if (f_get_alliance(f)) { centre(out, alliancename(f->alliance), true); diff --git a/src/report.test.c b/src/report.test.c index 4fa97825c..3c49b14fc 100644 --- a/src/report.test.c +++ b/src/report.test.c @@ -2,7 +2,6 @@ #include "report.h" #include "move.h" #include "travelthru.h" -#include "keyword.h" #include #include @@ -15,6 +14,8 @@ #include #include +#include "util/keyword.h" +#include "util/param.h" #include #include #include diff --git a/src/reports.c b/src/reports.c index 9d9ab5f6f..56c6fd2b1 100644 --- a/src/reports.c +++ b/src/reports.c @@ -62,9 +62,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "kernel/unit.h" /* util includes */ -#include "util/attrib.h" +#include "kernel/attrib.h" #include "util/base36.h" -#include "util/bsdstring.h" #include "util/functions.h" #include "util/goodies.h" #include "util/language.h" @@ -162,29 +161,37 @@ const char *combatstatus[] = { "status_avoid", "status_flee" }; -size_t report_status(const unit * u, const struct locale *lang, char *fsbuf, size_t buflen) +void report_status(const unit * u, const struct locale *lang, struct sbstring *sbp) { const char * status = LOC(lang, combatstatus[u->status]); - size_t len = 0; if (!status) { const char *lname = locale_name(lang); struct locale *wloc = get_locale(lname); + log_warning("no translation for combat status %s in %s", combatstatus[u->status], lname); locale_setstring(wloc, combatstatus[u->status], combatstatus[u->status] + 7); - len = str_strlcpy(fsbuf, combatstatus[u->status] + 7, buflen); + sbs_strcat(sbp, combatstatus[u->status] + 7); } else { - len = str_strlcpy(fsbuf, status, buflen); + sbs_strcat(sbp, status); } if (fval(u, UFL_NOAID)) { - len += str_strlcat(fsbuf + len, ", ", buflen - len); - len += str_strlcat(fsbuf + len, LOC(lang, "status_noaid"), buflen - len); + sbs_strcat(sbp, ", "); + sbs_strcat(sbp, LOC(lang, "status_noaid")); } - - return len; } +size_t report_status_depr(const unit * u, const struct locale *lang, char *fsbuf, size_t buflen) +{ + sbstring sbs; + + sbs_init(&sbs, fsbuf, buflen); + report_status(u, lang, &sbs); + return sbs_length(&sbs); +} + + const char *hp_status(const unit * u) { double p; @@ -274,29 +281,19 @@ report_item(const unit * owner, const item * i, const faction * viewer, } #define ORDERS_IN_NR 1 -static size_t buforder(char *buffer, size_t size, const order * ord, const struct locale *lang, int mode) +static void buforder(sbstring *sbp, const order * ord, const struct locale *lang, int mode) { - char *bufp = buffer; - - bufp = STRLCPY(bufp, ", \"", size); + sbs_strcat(sbp, ", \""); if (mode < ORDERS_IN_NR) { char cmd[ORDERSIZE]; get_command(ord, lang, cmd, sizeof(cmd)); - bufp = STRLCPY(bufp, cmd, size); + sbs_strcat(sbp, cmd); } else { - bufp = STRLCPY(bufp, "...", size); + sbs_strcat(sbp, "..."); } - if (size > 1) { - *bufp++ = '\"'; - --size; - } - else { - WARN_STATIC_BUFFER(); - } - - return bufp - buffer; + sbs_strcat(sbp, "\""); } /** create a report of a list of items to a non-owner. @@ -365,21 +362,24 @@ static void report_resource(resource_report * result, const resource_type *rtype result->level = level; } -void report_raceinfo(const struct race *rc, const struct locale *lang, char *buf, size_t length) +static void bufattack(struct sbstring *sbp, const struct locale *lang, const char *name, const char *dmg) { + sbs_strcat(sbp, LOC(lang, name)); + if (dmg) { + sbs_strcat(sbp, " ("); + sbs_strcat(sbp, dmg); + sbs_strcat(sbp, ")"); + } +} + +void report_raceinfo(const struct race *rc, const struct locale *lang, struct sbstring *sbp) { const char *info; int a, at_count; const char *name, *key; - char *bufp = buf; - size_t size = length - 1; - size_t bytes; name = rc_name_s(rc, NAME_SINGULAR); - - bytes = slprintf(bufp, size, "%s: ", LOC(lang, name)); - assert(bytes <= INT_MAX); - if (wrptr(&bufp, &size, (int)bytes) != 0) - WARN_STATIC_BUFFER(); + sbs_strcat(sbp, LOC(lang, name)); + sbs_strcat(sbp, ": "); key = mkname("raceinfo", rc->_name); info = locale_getstring(lang, key); @@ -387,47 +387,37 @@ void report_raceinfo(const struct race *rc, const struct locale *lang, char *buf info = LOC(lang, mkname("raceinfo", "no_info")); } - if (info) bufp = STRLCPY(bufp, info, size); + if (info) { + sbs_strcat(sbp, info); + } /* hp_p : Trefferpunkte */ - bytes = - slprintf(bufp, size, " %d %s", rc->hitpoints, LOC(lang, - "stat_hitpoints")); - assert(bytes <= INT_MAX); - if (wrptr(&bufp, &size, (int)bytes) != 0) - WARN_STATIC_BUFFER(); + sbs_strcat(sbp, " "); + sbs_strcat(sbp, str_itoa(rc->hitpoints)); + sbs_strcat(sbp, " "); + sbs_strcat(sbp, LOC(lang, "stat_hitpoints")); /* b_attacke : Angriff */ - bytes = - slprintf(bufp, size, ", %s: %d", LOC(lang, "stat_attack"), - (rc->at_default + rc->at_bonus)); - assert(bytes <= INT_MAX); - if (wrptr(&bufp, &size, (int)bytes) != 0) - WARN_STATIC_BUFFER(); + sbs_strcat(sbp, ", "); + sbs_strcat(sbp, LOC(lang, "stat_attack")); + sbs_strcat(sbp, ": "); + sbs_strcat(sbp, str_itoa(rc->at_default + rc->at_bonus)); /* b_defense : Verteidigung */ - bytes = - slprintf(bufp, size, ", %s: %d", LOC(lang, "stat_defense"), - (rc->df_default + rc->df_bonus)); - assert(bytes <= INT_MAX); - if (wrptr(&bufp, &size, (int)bytes) != 0) - WARN_STATIC_BUFFER(); + sbs_strcat(sbp, ", "); + sbs_strcat(sbp, LOC(lang, "stat_defense")); + sbs_strcat(sbp, ": "); + sbs_strcat(sbp, str_itoa(rc->df_default + rc->df_bonus)); /* b_armor : Rüstung */ if (rc->armor > 0) { - bytes = - slprintf(bufp, size, ", %s: %d", LOC(lang, "stat_armor"), rc->armor); - assert(bytes <= INT_MAX); - if (wrptr(&bufp, &size, (int)bytes) != 0) - WARN_STATIC_BUFFER(); + sbs_strcat(sbp, ", "); + sbs_strcat(sbp, LOC(lang, "stat_armor")); + sbs_strcat(sbp, ": "); + sbs_strcat(sbp, str_itoa(rc->armor)); } - if (size > 1) { - *bufp++ = '.'; - --size; - } - else - WARN_STATIC_BUFFER(); + sbs_strcat(sbp, "."); /* b_damage : Schaden */ at_count = 0; @@ -437,73 +427,53 @@ void report_raceinfo(const struct race *rc, const struct locale *lang, char *buf } } if (rc->battle_flags & BF_EQUIPMENT) { - if (wrptr(&bufp, &size, snprintf(bufp, size, " %s", LOC(lang, "stat_equipment"))) != 0) - WARN_STATIC_BUFFER(); + sbs_strcat(sbp, " "); + sbs_strcat(sbp, LOC(lang, "stat_equipment")); } if (rc->battle_flags & BF_RES_PIERCE) { - if (wrptr(&bufp, &size, snprintf(bufp, size, " %s", LOC(lang, "stat_pierce"))) != 0) - WARN_STATIC_BUFFER(); + sbs_strcat(sbp, " "); + sbs_strcat(sbp, LOC(lang, "stat_pierce")); } if (rc->battle_flags & BF_RES_CUT) { - if (wrptr(&bufp, &size, snprintf(bufp, size, " %s", LOC(lang, "stat_cut"))) != 0) - WARN_STATIC_BUFFER(); + sbs_strcat(sbp, " "); + sbs_strcat(sbp, LOC(lang, "stat_cut")); } if (rc->battle_flags & BF_RES_BASH) { - if (wrptr(&bufp, &size, snprintf(bufp, size, " %s", LOC(lang, "stat_bash"))) != 0) - WARN_STATIC_BUFFER(); + sbs_strcat(sbp, " "); + sbs_strcat(sbp, LOC(lang, "stat_bash")); } - if (wrptr(&bufp, &size, snprintf(bufp, size, " %d %s", at_count, LOC(lang, (at_count == 1) ? "stat_attack" : "stat_attacks"))) != 0) - WARN_STATIC_BUFFER(); + sbs_strcat(sbp, " "); + sbs_strcat(sbp, str_itoa(at_count)); + sbs_strcat(sbp, " "); + sbs_strcat(sbp, LOC(lang, (at_count == 1) ? "stat_attack" : "stat_attacks")); for (a = 0; a < RACE_ATTACKS; a++) { if (rc->attack[a].type != AT_NONE) { - if (a != 0) - bufp = STRLCPY(bufp, ", ", size); - else - bufp = STRLCPY(bufp, ": ", size); + sbs_strcat(sbp, (a == 0) ? ": " : ", "); switch (rc->attack[a].type) { case AT_STANDARD: - bytes = - (size_t)snprintf(bufp, size, "%s (%s)", - LOC(lang, "attack_standard"), rc->def_damage); + bufattack(sbp, lang, "attack_standard", rc->def_damage); break; case AT_NATURAL: - bytes = - (size_t)snprintf(bufp, size, "%s (%s)", - LOC(lang, "attack_natural"), rc->attack[a].data.dice); + bufattack(sbp, lang, "attack_natural", rc->attack[a].data.dice); break; case AT_SPELL: case AT_COMBATSPELL: case AT_DRAIN_ST: case AT_DRAIN_EXP: case AT_DAZZLE: - bytes = (size_t)snprintf(bufp, size, "%s", LOC(lang, "attack_magical")); + bufattack(sbp, lang, "attack_magical", NULL); break; case AT_STRUCTURAL: - bytes = - (size_t)snprintf(bufp, size, "%s (%s)", - LOC(lang, "attack_structural"), rc->attack[a].data.dice); + bufattack(sbp, lang, "attack_structural", rc->attack[a].data.dice); break; - default: - bytes = 0; } - - assert(bytes <= INT_MAX); - if (bytes && wrptr(&bufp, &size, (int)bytes) != 0) - WARN_STATIC_BUFFER(); } } - if (size > 1) { - *bufp++ = '.'; - --size; - } - else - WARN_STATIC_BUFFER(); - - *bufp = 0; + sbs_strcat(sbp, "."); } void @@ -612,50 +582,47 @@ report_resources(const region * r, resource_report * result, int size, return n; } -static size_t spskill(char *buffer, size_t size, const struct locale * lang, +static void spskill(sbstring *sbp, const struct locale * lang, const struct unit * u, struct skill * sv, int *dh) { - char *bufp = buffer; int effsk; - if (!u->number) - return 0; + if (!u->number) { + return; + } if (sv->level <= 0) { if (sv->old <= 0 || (u->faction->options & WANT_OPTION(O_SHOWSKCHANGE)) == 0) { - return 0; + return; } } - - bufp = STRLCPY(bufp, ", ", size); + sbs_strcat(sbp, ", "); if (!*dh) { - bufp = STRLCPY(bufp, LOC(lang, "nr_skills"), size); - bufp = STRLCPY(bufp, ": ", size); + sbs_strcat(sbp, LOC(lang, "nr_skills")); + sbs_strcat(sbp, ": "); *dh = 1; } - bufp = STRLCPY(bufp, skillname(sv->id, lang), size); - bufp = STRLCPY(bufp, " ", size); + sbs_strcat(sbp, skillname(sv->id, lang)); + sbs_strcat(sbp, " "); if (sv->id == SK_MAGIC) { - sc_mage *mage = get_mage(u); - if (mage && mage->magietyp != M_GRAY) { - bufp = STRLCPY(bufp, LOC(lang, mkname("school", - magic_school[mage->magietyp])), size); - bufp = STRLCPY(bufp, " ", size); + magic_t mtype = unit_get_magic(u); + if (mtype != M_GRAY) { + sbs_strcat(sbp, magic_name(mtype, lang)); + sbs_strcat(sbp, " "); } } if (sv->id == SK_STEALTH && fval(u, UFL_STEALTH)) { int i = u_geteffstealth(u); if (i >= 0) { - if (wrptr(&bufp, &size, snprintf(bufp, size, "%d/", i)) != 0) - WARN_STATIC_BUFFER(); + sbs_strcat(sbp, str_itoa(i)); + sbs_strcat(sbp, "/"); } } effsk = eff_skill(u, sv, 0); - if (wrptr(&bufp, &size, snprintf(bufp, size, "%d", effsk)) != 0) - WARN_STATIC_BUFFER(); + sbs_strcat(sbp, str_itoa(effsk)); if (u->faction->options & WANT_OPTION(O_SHOWSKCHANGE)) { int oldeff = 0; @@ -669,157 +636,137 @@ static size_t spskill(char *buffer, size_t size, const struct locale * lang, diff = effsk - oldeff; if (diff != 0) { - if (wrptr(&bufp, &size, snprintf(bufp, size, " (%s%d)", (diff > 0) ? "+" : "", diff)) != 0) - WARN_STATIC_BUFFER(); + sbs_strcat(sbp, " ("); + sbs_strcat(sbp, (diff > 0) ? "+" : ""); + sbs_strcat(sbp, str_itoa(diff)); + sbs_strcat(sbp, ")"); } } - return bufp - buffer; } -int -bufunit(const faction * f, const unit * u, seen_mode mode, char *buf, - size_t size) +void bufunit(const faction * f, const unit * u, const faction *fv, + seen_mode mode, int getarnt, struct sbstring *sbp) { int i, dh; - int getarnt = fval(u, UFL_ANON_FACTION); const char *pzTmp, *str; - building *b; - bool isbattle = (bool)(mode == seen_battle); + bool isbattle = (mode == seen_battle); item *itm, *show = NULL; - faction *fv; - char *bufp = buf; - int result = 0; item results[MAX_INVENTORY]; const struct locale *lang = f->locale; + if (!fv) { + fv = visible_faction(f, u); + } assert(f); - bufp = STRLCPY(bufp, unitname(u), size); - fv = visible_faction(f, u); + sbs_strcat(sbp, unitname(u)); if (!isbattle) { if (u->faction == f) { if (fval(u, UFL_GROUP)) { - attrib *a = a_find(u->attribs, &at_group); - if (a) { - group *g = (group *)a->data.v; - bufp = STRLCPY(bufp, ", ", size); - bufp = STRLCPY(bufp, groupid(g, f), size); + group *g = get_group(u); + if (g) { + sbs_strcat(sbp, ", "); + sbs_strcat(sbp, groupid(g, f)); } } if (getarnt) { - bufp = STRLCPY(bufp, ", ", size); - bufp = STRLCPY(bufp, LOC(lang, "anonymous"), size); + sbs_strcat(sbp, ", "); + sbs_strcat(sbp, LOC(lang, "anonymous")); } else if (u->attribs) { faction *otherf = get_otherfaction(u); if (otherf) { - bufp = STRLCPY(bufp, ", ", size); - bufp = STRLCPY(bufp, factionname(otherf), size); + sbs_strcat(sbp, ", "); + sbs_strcat(sbp, factionname(otherf)); } } } else { if (getarnt) { - bufp = STRLCPY(bufp, ", ", size); - bufp = STRLCPY(bufp, LOC(lang, "anonymous"), size); + sbs_strcat(sbp, ", "); + sbs_strcat(sbp, LOC(lang, "anonymous")); } else { if (u->attribs && alliedunit(u, f, HELP_FSTEALTH)) { faction *otherf = get_otherfaction(u); if (otherf) { - int n = snprintf(bufp, size, ", %s (%s)", - factionname(otherf), factionname(u->faction)); - if (wrptr(&bufp, &size, n) != 0) - WARN_STATIC_BUFFER(); + sbs_strcat(sbp, ", "); + sbs_strcat(sbp, factionname(otherf)); + sbs_strcat(sbp, " ("); + sbs_strcat(sbp, factionname(u->faction)); + sbs_strcat(sbp, ")"); } else { - bufp = STRLCPY(bufp, ", ", size); - bufp = STRLCPY(bufp, factionname(fv), size); + sbs_strcat(sbp, ", "); + sbs_strcat(sbp, factionname(fv)); } } else { - bufp = STRLCPY(bufp, ", ", size); - bufp = STRLCPY(bufp, factionname(fv), size); + sbs_strcat(sbp, ", "); + sbs_strcat(sbp, factionname(fv)); } } } } - bufp = STRLCPY(bufp, ", ", size); - - if (wrptr(&bufp, &size, snprintf(bufp, size, "%d ", u->number))) - WARN_STATIC_BUFFER(); + sbs_strcat(sbp, ", "); + sbs_strcat(sbp, str_itoa(u->number)); + sbs_strcat(sbp, " "); pzTmp = get_racename(u->attribs); if (pzTmp) { - bufp = STRLCPY(bufp, pzTmp, size); + sbs_strcat(sbp, pzTmp); if (u->faction == f && fval(u_race(u), RCF_SHAPESHIFTANY)) { - bufp = STRLCPY(bufp, " (", size); - bufp = STRLCPY(bufp, racename(lang, u, u_race(u)), size); - if (size > 1) { - strcpy(bufp++, ")"); - --size; - } + sbs_strcat(sbp, " ("); + sbs_strcat(sbp, racename(lang, u, u_race(u))); + sbs_strcat(sbp, ")"); } } else { const race *irace = u_irace(u); - bufp = STRLCPY(bufp, racename(lang, u, irace), size); - if (u->faction == f && irace != u_race(u)) { - bufp = STRLCPY(bufp, " (", size); - bufp = STRLCPY(bufp, racename(lang, u, u_race(u)), size); - if (size > 1) { - strcpy(bufp++, ")"); - --size; - } + const race *urace = u_race(u); + sbs_strcat(sbp, racename(lang, u, irace)); + if (u->faction == f && irace != urace) { + sbs_strcat(sbp, " ("); + sbs_strcat(sbp, racename(lang, u, urace)); + sbs_strcat(sbp, ")"); } } if (fval(u, UFL_HERO) && (u->faction == f || omniscient(f))) { - bufp = STRLCPY(bufp, ", ", size); - bufp = STRLCPY(bufp, LOC(lang, "hero"), size); + sbs_strcat(sbp, ", "); + sbs_strcat(sbp, LOC(lang, "hero")); } /* status */ if (u->number && (u->faction == f || isbattle)) { const char *c = hp_status(u); c = c ? LOC(lang, c) : 0; - bufp = STRLCPY(bufp, ", ", size); - bufp += report_status(u, lang, bufp, size); + sbs_strcat(sbp, ", "); + report_status(u, lang, sbp); if (c || fval(u, UFL_HUNGER)) { - bufp = STRLCPY(bufp, " (", size); + sbs_strcat(sbp, " ("); if (c) { - bufp = STRLCPY(bufp, c, size); + sbs_strcat(sbp, c); } if (fval(u, UFL_HUNGER)) { if (c) { - bufp = STRLCPY(bufp, ", ", size); + sbs_strcat(sbp, ", "); } - bufp = STRLCPY(bufp, LOC(lang, "unit_hungers"), size); - } - if (size > 1) { - strcpy(bufp++, ")"); - --size; + sbs_strcat(sbp, LOC(lang, "unit_hungers")); } + sbs_strcat(sbp, ")"); } } if (is_guard(u)) { - bufp = STRLCPY(bufp, ", ", size); - bufp = STRLCPY(bufp, LOC(lang, "unit_guards"), size); - } - - if ((b = usiege(u)) != NULL) { - bufp = STRLCPY(bufp, ", belagert ", size); - bufp = STRLCPY(bufp, buildingname(b), size); + sbs_strcat(sbp, ", "); + sbs_strcat(sbp, LOC(lang, "unit_guards")); } dh = 0; if (u->faction == f) { skill *sv; for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { - size_t bytes = spskill(bufp, size, lang, u, sv, &dh); - assert(bytes <= INT_MAX); - if (wrptr(&bufp, &size, (int)bytes) != 0) - WARN_STATIC_BUFFER(); + spskill(sbp, lang, u, sv, &dh); } } @@ -838,22 +785,23 @@ bufunit(const faction * f, const unit * u, seen_mode mode, char *buf, const char *ic; int in; report_item(u, itm, f, &ic, NULL, &in, false); - if (in == 0 || ic == NULL) + if (in == 0 || ic == NULL) { continue; - bufp = STRLCPY(bufp, ", ", size); + } + sbs_strcat(sbp, ", "); if (!dh) { - result = snprintf(bufp, size, "%s: ", LOC(lang, "nr_inventory")); - if (wrptr(&bufp, &size, result) != 0) - WARN_STATIC_BUFFER(); + sbs_strcat(sbp, LOC(lang, "nr_inventory")); + sbs_strcat(sbp, ": "); dh = 1; } if (in == 1) { - bufp = STRLCPY(bufp, ic, size); + sbs_strcat(sbp, ic); } else { - if (wrptr(&bufp, &size, snprintf(bufp, size, "%d %s", in, ic))) - WARN_STATIC_BUFFER(); + sbs_strcat(sbp, str_itoa(in)); + sbs_strcat(sbp, " "); + sbs_strcat(sbp, ic); } } @@ -863,27 +811,26 @@ bufunit(const faction * f, const unit * u, seen_mode mode, char *buf, if (book) { selist *ql = book->spells; int qi, header, maxlevel = effskill(u, SK_MAGIC, 0); - int n = snprintf(bufp, size, ". Aura %d/%d", get_spellpoints(u), max_spellpoints(u->region, u)); - if (wrptr(&bufp, &size, n) != 0) { - WARN_STATIC_BUFFER(); - } + sbs_strcat(sbp, ". Aura "); + sbs_strcat(sbp, str_itoa(get_spellpoints(u))); + sbs_strcat(sbp, "/"); + sbs_strcat(sbp, str_itoa(max_spellpoints(u, NULL))); for (header = 0, qi = 0; ql; selist_advance(&ql, &qi, 1)) { spellbook_entry * sbe = (spellbook_entry *)selist_get(ql, qi); const spell *sp = spellref_get(&sbe->spref); if (sbe->level <= maxlevel) { if (!header) { - n = snprintf(bufp, size, ", %s: ", LOC(lang, "nr_spells")); + sbs_strcat(sbp, ", "); + sbs_strcat(sbp, LOC(lang, "nr_spells")); + sbs_strcat(sbp, ": "); header = 1; } else { - n = (int)str_strlcpy(bufp, ", ", size); - } - if (wrptr(&bufp, &size, n) != 0) { - WARN_STATIC_BUFFER(); + sbs_strcat(sbp, ", "); } /* TODO: no need to deref the spellref here (spref->name is good) */ - bufp = STRLCPY(bufp, spell_name(sp, lang), size); + sbs_strcat(sbp, spell_name(sp, lang)); } } @@ -892,10 +839,9 @@ bufunit(const faction * f, const unit * u, seen_mode mode, char *buf, break; } if (i != MAXCOMBATSPELLS) { - n = snprintf(bufp, size, ", %s: ", LOC(lang, "nr_combatspells")); - if (wrptr(&bufp, &size, n) != 0) - WARN_STATIC_BUFFER(); - + sbs_strcat(sbp, ", "); + sbs_strcat(sbp, LOC(lang, "nr_combatspells")); + sbs_strcat(sbp, ": "); dh = 0; for (i = 0; i < MAXCOMBATSPELLS; i++) { const spell *sp; @@ -903,86 +849,83 @@ bufunit(const faction * f, const unit * u, seen_mode mode, char *buf, dh = 1; } else { - bufp = STRLCPY(bufp, ", ", size); + sbs_strcat(sbp, ", "); } sp = get_combatspell(u, i); if (sp) { int sl = get_combatspelllevel(u, i); - bufp = STRLCPY(bufp, spell_name(sp, lang), size); + sbs_strcat(sbp, spell_name(sp, lang)); if (sl > 0) { - n = snprintf(bufp, size, " (%d)", sl); - if (wrptr(&bufp, &size, n) != 0) - WARN_STATIC_BUFFER(); + sbs_strcat(sbp, "( "); + sbs_strcat(sbp, str_itoa(sl)); + sbs_strcat(sbp, ")"); } } else { - bufp = STRLCPY(bufp, LOC(lang, "nr_nospells"), size); + sbs_strcat(sbp, LOC(lang, "nr_nospells")); } } } } if (!isbattle) { int printed = 0; - order *ord;; + order *ord; for (ord = u->old_orders; ord; ord = ord->next) { keyword_t kwd = getkeyword(ord); if (is_repeated(kwd)) { - if (printed < ORDERS_IN_NR) { - int n = (int)buforder(bufp, size, ord, u->faction->locale, printed++); - if (wrptr(&bufp, &size, n) != 0) - WARN_STATIC_BUFFER(); - } - else + if (printed >= ORDERS_IN_NR) { break; + } + buforder(sbp, ord, u->faction->locale, printed++); } } - if (printed < ORDERS_IN_NR) + if (printed < ORDERS_IN_NR) { for (ord = u->orders; ord; ord = ord->next) { keyword_t kwd = getkeyword(ord); if (is_repeated(kwd)) { - if (printed < ORDERS_IN_NR) { - int n = (int)buforder(bufp, size, ord, lang, printed++); - if (wrptr(&bufp, &size, n) != 0) - WARN_STATIC_BUFFER(); - } - else { + if (printed >= ORDERS_IN_NR) { break; } + buforder(sbp, ord, lang, printed++); } } + } } } i = 0; str = u_description(u, lang); if (str) { - bufp = STRLCPY(bufp, "; ", size); - bufp = STRLCPY(bufp, str, size); + sbs_strcat(sbp, "; "); + sbs_strcat(sbp, str); i = str[strlen(str) - 1]; } if (i != '!' && i != '?' && i != '.') { - if (size > 1) { - strcpy(bufp++, "."); - --size; - } + sbs_strcat(sbp, "."); } pzTmp = uprivate(u); if (u->faction == f && pzTmp) { - bufp = STRLCPY(bufp, " (Bem: ", size); - bufp = STRLCPY(bufp, pzTmp, size); - bufp = STRLCPY(bufp, ")", size); + sbs_strcat(sbp, " (Bem: "); + sbs_strcat(sbp, pzTmp); + sbs_strcat(sbp, ")"); } +} - dh = 0; +int bufunit_depr(const faction * f, const unit * u, seen_mode mode, + char *buf, size_t size) +{ + int getarnt = fval(u, UFL_ANON_FACTION); + const faction * fv = visible_faction(f, u); + sbstring sbs; + + sbs_init(&sbs, buf, size); + bufunit(f, u, fv, mode, getarnt, &sbs); if (!getarnt) { - if (alliedfaction(rplane(u->region), f, fv, HELP_ALL)) { - dh = 1; + if (alliedfaction(f, fv, HELP_ALL)) { + return 1; } } - if (size <= 1) { - log_warning("bufunit ran out of space after writing %u bytes.\n", (bufp - buf)); - } - return dh; + return 0; } void split_paragraph(strlist ** SP, const char *s, unsigned int indent, unsigned int width, char mark) @@ -1056,7 +999,7 @@ spunit(struct strlist **SP, const struct faction *f, const unit * u, unsigned in seen_mode mode) { char buf[DISPLAYSIZE]; - int dh = bufunit(f, u, mode, buf, sizeof(buf)); + int dh = bufunit_depr(f, u, mode, buf, sizeof(buf)); lparagraph(SP, buf, indent, (char)((u->faction == f) ? '*' : (dh ? '+' : '-'))); } @@ -1140,7 +1083,6 @@ static void cb_add_address(region *r, unit *ut, void *cbdata) { if (data->lastf != sf && cansee_unit(ut, u, data->stealthmod)) { add_seen_faction_i(data->flist, sf); data->lastf = sf; - break; } } } @@ -1560,14 +1502,6 @@ void prepare_report(report_context *ctx, faction *f) rule_lighthouse_units = config_get_int("rules.lighthouse.unit_capacity", 0) != 0; } - if (f->age <= 2) { - if ((f->flags&FFL_PWMSG) == 0) { - /* TODO: this assumes unencrypted passwords */ - f->flags |= FFL_PWMSG; - ADDMSG(&f->msgs, msg_message("changepasswd", "value", f->_password)); - } - } - ctx->f = f; ctx->report_time = time(NULL); ctx->addresses = NULL; @@ -2214,28 +2148,23 @@ static void eval_resources(struct opstack **stack, const void *userdata) const struct locale *lang = f ? f->locale : default_locale; const struct resource *res = (const struct resource *)opop(stack).v; char buf[1024]; /* but we only use about half of this */ - size_t size = sizeof(buf) - 1; variant var; - - char *bufp = buf; - while (res != NULL && size > 4) { + sbstring sbs; + + sbs_init(&sbs, buf, sizeof(buf)); + while (res != NULL) { const char *rname = resourcename(res->type, (res->number != 1) ? NMF_PLURAL : 0); - int result = snprintf(bufp, size, "%d %s", res->number, LOC(lang, rname)); - if (wrptr(&bufp, &size, result) != 0 || size < sizeof(buf) / 2) { - WARN_STATIC_BUFFER(); - break; - } + sbs_strcat(&sbs, str_itoa(res->number)); + sbs_strcat(&sbs, ""); + sbs_strcat(&sbs, LOC(lang, rname)); res = res->next; - if (res != NULL && size > 2) { - strcat(bufp, ", "); - bufp += 2; - size -= 2; + if (res != NULL) { + sbs_strcat(&sbs, ", "); } } - *bufp = 0; - var.v = strcpy(balloc((size_t)(bufp - buf + 1)), buf); + var.v = strcpy(balloc(sbs_length(&sbs)), buf); opush(stack, var); } @@ -2246,31 +2175,29 @@ static void eval_regions(struct opstack **stack, const void *userdata) int handle_end, begin = opop(stack).i; const arg_regions *aregs = (const arg_regions *)opop(stack).v; char buf[256]; - size_t size = sizeof(buf) - 1; variant var; - char *bufp = buf; + sbstring sbs; + sbs_init(&sbs, buf, sizeof(buf)); if (aregs == NULL) { handle_end = begin; } - else { - if (i >= 0) - handle_end = begin + i; - else - handle_end = aregs->nregions + i; + else if (i >= 0) { + handle_end = begin + i; } + else { + handle_end = aregs->nregions + i; + } + for (i = begin; i < handle_end; ++i) { const char *rname = (const char *)regionname(aregs->regions[i], report); - bufp = STRLCPY(bufp, rname, size); + sbs_strcat(&sbs, rname); - if (i + 1 < handle_end && size > 2) { - strcat(bufp, ", "); - bufp += 2; - size -= 2; + if (i + 1 < handle_end) { + sbs_strcat(&sbs, ", "); } } - *bufp = 0; - var.v = strcpy(balloc((size_t)(bufp - buf + 1)), buf); + var.v = strcpy(balloc(sbs_length(&sbs)), buf); opush(stack, var); } @@ -2281,41 +2208,49 @@ const char *get_mailcmd(const struct locale *loc) return result; } +static void print_trail(const faction *f, const region *r, + const struct locale *lang, struct sbstring *sbp) +{ + char buf[64]; + const char *trail = trailinto(r, lang); + const char *rn = f_regionid_s(r, f); + if (snprintf(buf, sizeof(buf), trail, rn) != 0) { + sbs_strcat(sbp, buf); + } +} + static void eval_trail(struct opstack **stack, const void *userdata) { /* order -> string */ const faction *report = (const faction *)userdata; const struct locale *lang = report ? report->locale : default_locale; const arg_regions *aregs = (const arg_regions *)opop(stack).v; char buf[512]; - size_t size = sizeof(buf) - 1; variant var; - char *bufp = buf; + sbstring sbs; #ifdef _SECURECRT_ERRCODE_VALUES_DEFINED - /* stupid MS broke snprintf */ + /* MSVC touches errno in snprintf */ int eold = errno; #endif + sbs_init(&sbs, buf, sizeof(buf)); if (aregs != NULL) { int i, handle_end = 0, begin = 0; handle_end = aregs->nregions; for (i = begin; i < handle_end; ++i) { region *r = aregs->regions[i]; - const char *trail = trailinto(r, lang); - const char *rn = f_regionid_s(r, report); + sbs_strcat(&sbs, ", "); - if (wrptr(&bufp, &size, snprintf(bufp, size, trail, rn)) != 0) - WARN_STATIC_BUFFER(); + print_trail(report, r, lang, &sbs); if (i + 2 < handle_end) { - bufp = STRLCPY(bufp, ", ", size); + sbs_strcat(&sbs, ", "); } else if (i + 1 < handle_end) { - bufp = STRLCPY(bufp, LOC(lang, "list_and"), size); + sbs_strcat(&sbs, LOC(lang, "list_and")); } } } - *bufp = 0; - var.v = strcpy(balloc((size_t)(bufp - buf + 1)), buf); + var.v = strcpy(balloc(sbs_length(&sbs)), buf); opush(stack, var); #ifdef _SECURECRT_ERRCODE_VALUES_DEFINED if (errno == ERANGE) { @@ -2324,11 +2259,9 @@ static void eval_trail(struct opstack **stack, const void *userdata) #endif } -void report_race_skills(const race *rc, char *zText, size_t length, const struct locale *lang) +void report_race_skills(const race *rc, const struct locale *lang, sbstring *sbp) { - size_t size = length - 1; int dh = 0, dh1 = 0, sk; - char *bufp = zText; for (sk = 0; sk < MAXSKILLS; ++sk) { if (skill_enabled(sk) && rc->bonus[sk] > -5) @@ -2337,29 +2270,30 @@ void report_race_skills(const race *rc, char *zText, size_t length, const struct for (sk = 0; sk < MAXSKILLS; sk++) { if (skill_enabled(sk) && rc->bonus[sk] > -5) { - size_t bytes; dh--; if (dh1 == 0) { dh1 = 1; } else { if (dh == 0) { - bytes = str_strlcpy(bufp, LOC(lang, "list_and"), size); + sbs_strcat(sbp, LOC(lang, "list_and")); } else { - bytes = str_strlcpy(bufp, ", ", size); + sbs_strcat(sbp, ", "); } - assert(bytes <= INT_MAX); - BUFFER_STRCAT(bufp, size, bytes); } - bytes = str_strlcpy(bufp, skillname((skill_t)sk, lang), - size); - assert(bytes <= INT_MAX); - BUFFER_STRCAT(bufp, size, (int)bytes); + sbs_strcat(sbp, skillname((skill_t)sk, lang)); } } } +void report_race_skills_depr(const race *rc, char *zText, size_t length, const struct locale *lang) +{ + sbstring sbs; + sbs_init(&sbs, zText, length); + report_race_skills(rc, lang, &sbs); +} + static void eval_direction(struct opstack **stack, const void *userdata) { const faction *report = (const faction *)userdata; diff --git a/src/reports.h b/src/reports.h index a6dddb1b4..91af51bc2 100644 --- a/src/reports.h +++ b/src/reports.h @@ -31,6 +31,7 @@ extern "C" { struct battle; struct gamedate; + struct sbstring; struct selist; struct stream; struct seen_region; @@ -87,12 +88,15 @@ extern "C" { void register_reporttype(const char *extension, report_fun write, int flag); - int bufunit(const struct faction *f, const struct unit *u, seen_mode mode, + int bufunit_depr(const struct faction *f, const struct unit *u, seen_mode mode, char *buf, size_t size); + void bufunit(const struct faction * f, const struct unit * u, + const struct faction *fv, seen_mode mode, int getarnt, + struct sbstring *sbp); const char *trailinto(const struct region *r, const struct locale *lang); - size_t report_status(const struct unit *u, + size_t report_status_depr(const struct unit *u, const struct locale *lang, char *buf, size_t siz); void report_battle_start(struct battle * b); @@ -116,8 +120,8 @@ extern "C" { int report_items(const struct unit *u, struct item *result, int size, const struct unit *owner, const struct faction *viewer); void report_warnings(struct faction *f, int now); - void report_raceinfo(const struct race *rc, const struct locale *lang, char *buf, size_t length); - void report_race_skills(const struct race *rc, char *zText, size_t length, const struct locale *lang); + void report_raceinfo(const struct race *rc, const struct locale *lang, struct sbstring *sbp); + void report_race_skills_depr(const struct race *rc, char *zText, size_t length, const struct locale *lang); void report_item(const struct unit *owner, const struct item *i, const struct faction *viewer, const char **name, const char **basename, int *number, bool singular); diff --git a/src/reports.test.c b/src/reports.test.c index 6c19719e2..86f69b0fd 100644 --- a/src/reports.test.c +++ b/src/reports.test.c @@ -2,7 +2,7 @@ #include "reports.h" #include "guard.h" -#include "keyword.h" +#include "util/keyword.h" #include "lighthouse.h" #include "laws.h" #include "move.h" @@ -25,7 +25,7 @@ #include "kernel/spellbook.h" #include "kernel/terrain.h" -#include "util/attrib.h" +#include "kernel/attrib.h" #include "util/language.h" #include "util/lists.h" #include "util/message.h" @@ -76,7 +76,7 @@ static void test_reorder_units(CuTest * tc) CuAssertPtrEquals(tc, u2, u3->next); CuAssertPtrEquals(tc, u1, u2->next); CuAssertPtrEquals(tc, u0, u1->next); - CuAssertPtrEquals(tc, 0, u0->next); + CuAssertPtrEquals(tc, NULL, u0->next); test_teardown(); } @@ -130,19 +130,19 @@ static void test_sparagraph(CuTest *tc) { split_paragraph(&sp, "Hello World", 0, 16, 0); CuAssertPtrNotNull(tc, sp); CuAssertStrEquals(tc, "Hello World", sp->s); - CuAssertPtrEquals(tc, 0, sp->next); + CuAssertPtrEquals(tc, NULL, sp->next); freestrlist(sp); split_paragraph(&sp, "Hello World", 4, 16, 0); CuAssertPtrNotNull(tc, sp); CuAssertStrEquals(tc, " Hello World", sp->s); - CuAssertPtrEquals(tc, 0, sp->next); + CuAssertPtrEquals(tc, NULL, sp->next); freestrlist(sp); split_paragraph(&sp, "Hello World", 4, 16, '*'); CuAssertPtrNotNull(tc, sp); CuAssertStrEquals(tc, " * Hello World", sp->s); - CuAssertPtrEquals(tc, 0, sp->next); + CuAssertPtrEquals(tc, NULL, sp->next); freestrlist(sp); split_paragraph(&sp, "12345678 90 12345678", 0, 8, '*'); @@ -152,7 +152,7 @@ static void test_sparagraph(CuTest *tc) { CuAssertStrEquals(tc, "90", sp->next->s); CuAssertPtrNotNull(tc, sp->next->next); CuAssertStrEquals(tc, "12345678", sp->next->next->s); - CuAssertPtrEquals(tc, 0, sp->next->next->next); + CuAssertPtrEquals(tc, NULL, sp->next->next->next); freestrlist(sp); } @@ -177,7 +177,6 @@ static void test_bufunit_fstealth(CuTest *tc) { faction *f1, *f2; region *r; unit *u; - ally *al; char buf[256]; struct locale *lang; @@ -200,56 +199,55 @@ static void test_bufunit_fstealth(CuTest *tc) { key_set(&u->attribs, 42, 42); /* report to ourselves */ - bufunit(f1, u, seen_unit, buf, sizeof(buf)); + bufunit_depr(f1, u, seen_unit, buf, sizeof(buf)); CuAssertStrEquals(tc, "Hodor (1), 1 human, aggressive.", buf); /* ... also when we are anonymous */ u->flags |= UFL_ANON_FACTION; - bufunit(f1, u, seen_unit, buf, sizeof(buf)); + bufunit_depr(f1, u, seen_unit, buf, sizeof(buf)); CuAssertStrEquals(tc, "Hodor (1), anonymous, 1 human, aggressive.", buf); u->flags &= ~UFL_ANON_FACTION; /* we see that our unit is cloaked */ set_factionstealth(u, f2); CuAssertPtrNotNull(tc, u->attribs); - bufunit(f1, u, seen_unit, buf, sizeof(buf)); + bufunit_depr(f1, u, seen_unit, buf, sizeof(buf)); CuAssertStrEquals(tc, "Hodor (1), TWW (2), 1 human, aggressive.", buf); /* ... also when we are anonymous */ u->flags |= UFL_ANON_FACTION; - bufunit(f1, u, seen_unit, buf, sizeof(buf)); + bufunit_depr(f1, u, seen_unit, buf, sizeof(buf)); CuAssertStrEquals(tc, "Hodor (1), anonymous, 1 human, aggressive.", buf); u->flags &= ~UFL_ANON_FACTION; /* we can see that someone is presenting as us */ - bufunit(f2, u, seen_unit, buf, sizeof(buf)); + bufunit_depr(f2, u, seen_unit, buf, sizeof(buf)); CuAssertStrEquals(tc, "Hodor (1), TWW (2), 1 human.", buf); /* ... but not if they are anonymous */ u->flags |= UFL_ANON_FACTION; - bufunit(f2, u, seen_unit, buf, sizeof(buf)); + bufunit_depr(f2, u, seen_unit, buf, sizeof(buf)); CuAssertStrEquals(tc, "Hodor (1), anonymous, 1 human.", buf); u->flags &= ~UFL_ANON_FACTION; /* we see the same thing as them when we are an ally */ - al = ally_add(&f1->allies, f2); - al->status = HELP_FSTEALTH; - bufunit(f2, u, seen_unit, buf, sizeof(buf)); + ally_set(&f1->allies, f2, HELP_FSTEALTH); + bufunit_depr(f2, u, seen_unit, buf, sizeof(buf)); CuAssertStrEquals(tc, "Hodor (1), TWW (2) (UFO (1)), 1 human.", buf); /* ... also when they are anonymous */ u->flags |= UFL_ANON_FACTION; - bufunit(f2, u, seen_unit, buf, sizeof(buf)); + bufunit_depr(f2, u, seen_unit, buf, sizeof(buf)); CuAssertStrEquals(tc, "Hodor (1), anonymous, 1 human.", buf); u->flags &= ~UFL_ANON_FACTION; /* fstealth has no influence when we are allies, same results again */ set_factionstealth(u, NULL); - bufunit(f2, u, seen_unit, buf, sizeof(buf)); + bufunit_depr(f2, u, seen_unit, buf, sizeof(buf)); CuAssertStrEquals(tc, "Hodor (1), UFO (1), 1 human.", buf); u->flags |= UFL_ANON_FACTION; - bufunit(f2, u, seen_unit, buf, sizeof(buf)); + bufunit_depr(f2, u, seen_unit, buf, sizeof(buf)); CuAssertStrEquals(tc, "Hodor (1), anonymous, 1 human.", buf); u->flags &= ~UFL_ANON_FACTION; @@ -279,20 +277,20 @@ static void test_bufunit(CuTest *tc) { unit_setname(u, "Hodor"); unit_setid(u, 1); - bufunit(u->faction, u, 0, buffer, sizeof(buffer)); + bufunit_depr(u->faction, u, 0, buffer, sizeof(buffer)); CuAssertStrEquals(tc, "Hodor (1), 1 human, aggressiv.", buffer); set_level(u, SK_ALCHEMY, 1); - bufunit(u->faction, u, 0, buffer, sizeof(buffer)); + bufunit_depr(u->faction, u, 0, buffer, sizeof(buffer)); CuAssertStrEquals(tc, "Hodor (1), 1 human, aggressiv, Talente: Alchemie 2.", buffer); set_level(u, SK_SAILING, 1); - bufunit(u->faction, u, 0, buffer, sizeof(buffer)); + bufunit_depr(u->faction, u, 0, buffer, sizeof(buffer)); CuAssertStrEquals(tc, "Hodor (1), 1 human, aggressiv, Talente: Alchemie 2, Segeln 1.", buffer); f = test_create_faction(NULL); f->locale = get_or_create_locale("de"); - bufunit(f, u, 0, buffer, sizeof(buffer)); + bufunit_depr(f, u, 0, buffer, sizeof(buffer)); CuAssertStrEquals(tc, "Hodor (1), UFO (1), 1 human.", buffer); test_teardown(); @@ -326,7 +324,7 @@ static void test_arg_resources(CuTest *tc) { CuAssertPtrNotNull(tc, res = res->next); CuAssertPtrEquals(tc, itype->rtype, (void *)res->type); CuAssertIntEquals(tc, 5, res->number); - CuAssertPtrEquals(tc, 0, res->next); + CuAssertPtrEquals(tc, NULL, res->next); atype->release(v2); test_teardown(); } @@ -340,7 +338,7 @@ static void test_newbie_password_message(CuTest *tc) { f->flags = 0; prepare_report(&ctx, f); CuAssertIntEquals(tc, 0, f->flags&FFL_PWMSG); - CuAssertPtrEquals(tc, 0, test_find_messagetype(f->msgs, "changepasswd")); + CuAssertPtrEquals(tc, NULL, test_find_messagetype(f->msgs, "changepasswd")); f->age=2; prepare_report(&ctx, f); CuAssertIntEquals(tc, FFL_PWMSG, f->flags&FFL_PWMSG); @@ -442,22 +440,34 @@ static void test_get_addresses_fstealth(CuTest *tc) { static void test_get_addresses_travelthru(CuTest *tc) { report_context ctx; - faction *f, *f2, *f1; + faction *f, *f4, *f3, *f2, *f1; region *r1, *r2; unit *u; + race *rc; test_setup(); f = test_create_faction(NULL); - f1 = test_create_faction(NULL); - f2 = test_create_faction(NULL); r1 = test_create_region(0, 0, NULL); r2 = test_create_region(1, 0, 0); u = test_create_unit(f, r2); travelthru_add(r1, u); + + f1 = test_create_faction(NULL); u = test_create_unit(f1, r1); + f2 = test_create_faction(NULL); set_factionstealth(u, f2); u->building = test_create_building(u->region, test_create_buildingtype("tower")); + rc = rc_get_or_create("dragon"); + rc->flags |= RCF_UNARMEDGUARD; + f3 = test_create_faction(rc); + u = test_create_unit(f3, r1); + setguard(u, true); + + f4 = test_create_faction(NULL); + u = test_create_unit(f4, r1); + set_level(u, SK_STEALTH, 1); + prepare_report(&ctx, f); CuAssertPtrEquals(tc, r1, ctx.first); CuAssertPtrEquals(tc, NULL, ctx.last); @@ -466,7 +476,9 @@ static void test_get_addresses_travelthru(CuTest *tc) { CuAssertTrue(tc, selist_contains(ctx.addresses, f, NULL)); CuAssertTrue(tc, !selist_contains(ctx.addresses, f1, NULL)); CuAssertTrue(tc, selist_contains(ctx.addresses, f2, NULL)); - CuAssertIntEquals(tc, 2, selist_length(ctx.addresses)); + CuAssertTrue(tc, selist_contains(ctx.addresses, f3, NULL)); + CuAssertTrue(tc, !selist_contains(ctx.addresses, f4, NULL)); + CuAssertIntEquals(tc, 3, selist_length(ctx.addresses)); finish_reports(&ctx); test_teardown(); } @@ -511,7 +523,7 @@ void test_prepare_lighthouse_capacity(CuTest *tc) { prepare_report(&ctx, u2->faction); CuAssertPtrEquals(tc, r1, ctx.first); - CuAssertPtrEquals(tc, 0, ctx.last); + CuAssertPtrEquals(tc, NULL, ctx.last); CuAssertIntEquals(tc, seen_unit, r1->seen.mode); CuAssertIntEquals(tc, seen_neighbour, r2->seen.mode); finish_reports(&ctx); @@ -520,7 +532,7 @@ void test_prepare_lighthouse_capacity(CuTest *tc) { config_set_int("rules.lighthouse.unit_capacity", 1); prepare_report(&ctx, u2->faction); CuAssertPtrEquals(tc, r1, ctx.first); - CuAssertPtrEquals(tc, 0, ctx.last); + CuAssertPtrEquals(tc, NULL, ctx.last); CuAssertIntEquals(tc, seen_unit, r1->seen.mode); CuAssertIntEquals(tc, seen_lighthouse, r2->seen.mode); finish_reports(&ctx); @@ -619,15 +631,15 @@ static void test_prepare_report(CuTest *tc) { r = test_create_region(0, 0, NULL); prepare_report(&ctx, f); - CuAssertPtrEquals(tc, 0, ctx.first); - CuAssertPtrEquals(tc, 0, ctx.last); + CuAssertPtrEquals(tc, NULL, ctx.first); + CuAssertPtrEquals(tc, NULL, ctx.last); CuAssertIntEquals(tc, seen_none, r->seen.mode); finish_reports(&ctx); test_create_unit(f, r); prepare_report(&ctx, f); CuAssertPtrEquals(tc, r, ctx.first); - CuAssertPtrEquals(tc, 0, ctx.last); + CuAssertPtrEquals(tc, NULL, ctx.last); CuAssertIntEquals(tc, seen_unit, r->seen.mode); finish_reports(&ctx); CuAssertIntEquals(tc, seen_none, r->seen.mode); @@ -655,7 +667,7 @@ static void test_seen_neighbours(CuTest *tc) { test_create_unit(f, r1); prepare_report(&ctx, f); CuAssertPtrEquals(tc, r1, ctx.first); - CuAssertPtrEquals(tc, 0, ctx.last); + CuAssertPtrEquals(tc, NULL, ctx.last); CuAssertIntEquals(tc, seen_unit, r1->seen.mode); CuAssertIntEquals(tc, seen_neighbour, r2->seen.mode); finish_reports(&ctx); @@ -682,7 +694,7 @@ static void test_seen_travelthru(CuTest *tc) { CuAssertPtrEquals(tc, r3, f->last); prepare_report(&ctx, f); CuAssertPtrEquals(tc, r1, ctx.first); - CuAssertPtrEquals(tc, 0, ctx.last); + CuAssertPtrEquals(tc, NULL, ctx.last); CuAssertIntEquals(tc, seen_unit, r1->seen.mode); CuAssertIntEquals(tc, seen_travel, r2->seen.mode); CuAssertIntEquals(tc, seen_neighbour, r3->seen.mode); @@ -760,7 +772,7 @@ static void test_report_far_vision(CuTest *tc) { report_context ctx; prepare_report(&ctx, f); CuAssertPtrEquals(tc, r1, ctx.first); - CuAssertPtrEquals(tc, 0, ctx.last); + CuAssertPtrEquals(tc, NULL, ctx.last); CuAssertIntEquals(tc, seen_unit, r1->seen.mode); CuAssertIntEquals(tc, seen_spell, r2->seen.mode); finish_reports(&ctx); @@ -900,7 +912,7 @@ CuSuite *get_reports_suite(void) SUITE_ADD_TEST(suite, test_region_distance); SUITE_ADD_TEST(suite, test_region_distance_max); SUITE_ADD_TEST(suite, test_region_distance_ql); - SUITE_ADD_TEST(suite, test_newbie_password_message); + DISABLE_TEST(suite, test_newbie_password_message); SUITE_ADD_TEST(suite, test_prepare_report); SUITE_ADD_TEST(suite, test_seen_neighbours); SUITE_ADD_TEST(suite, test_seen_travelthru); diff --git a/src/settings.h b/src/settings.h index 57edb1566..498786be9 100644 --- a/src/settings.h +++ b/src/settings.h @@ -10,23 +10,11 @@ without prior permission by the authors of Eressea. */ -#define ENTERTAINFRACTION 20 -#define TEACHDIFFERENCE 2 #define RESOURCE_QUANTITY 0.5 #define RECRUITFRACTION 40 /* 100/RECRUITFRACTION% */ -#define COMBAT_TURNS 5 -#undef NEWATSROI - -/* Vermehrungsrate Bauern in 1/10000. -* TODO: Evt. Berechnungsfehler, reale Vermehrungsraten scheinen hoeher. */ -#define PEASANTGROWTH 10 -#define PEASANTLUCK 10 - -#define ROW_FACTOR 3 /* factor for combat row advancement rule */ /* TODO: move these settings to settings.h or into configuration files */ #define TREESIZE (8) /* space used by trees (in #peasants) */ -#define PEASANTFORCE 0.75 /* Chance einer Vermehrung trotz 90% Auslastung */ /* Gebaeudegroesse = Minimalbelagerer */ #define SIEGEFACTOR 2 diff --git a/src/skill.c b/src/skill.c index 2521befc6..abeecca04 100644 --- a/src/skill.c +++ b/src/skill.c @@ -5,6 +5,8 @@ #include #include #include +#include + #include #include diff --git a/src/spells.c b/src/spells.c index 8caf29039..b29e86ea9 100644 --- a/src/spells.c +++ b/src/spells.c @@ -17,6 +17,7 @@ #include "spells.h" +#include "contact.h" #include "guard.h" #include "reports.h" #include "spy.h" @@ -70,10 +71,10 @@ /* util includes */ #include -#include +#include #include -#include -#include +#include +#include #include #include #include @@ -475,8 +476,21 @@ report_effect(region * r, unit * mage, message * seen, message * unseen) static const race *select_familiar(const race * magerace, magic_t magiegebiet) { - const race *retval = 0; + const race *retval; int rnd = rng_int() % 100; + static const race *rcfixed; + static int config; + + if (config_changed(&config)) { + const char *rcname = config_get("magic.familiar.race"); + rcfixed = NULL; + if (rcname) { + rcfixed = rc_find(rcname); + } + } + if (rcfixed) { + return rcfixed; + } assert(magerace->familiars[0]); if (rnd >= 70) { @@ -533,19 +547,19 @@ static unit * make_familiar(unit * mage, region *r, const race *rc, const char * static int sp_summon_familiar(castorder * co) { region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *caster = co_get_caster(co); int cast_level = co->level; const race *rc; message *msg; char zText[2048]; - if (get_familiar(mage) != NULL) { - cmistake(mage, co->order, 199, MSG_MAGIC); + if (get_familiar(caster) != NULL) { + cmistake(caster, co->order, 199, MSG_MAGIC); return 0; } - rc = select_familiar(mage->_race, mage->faction->magiegebiet); + rc = select_familiar(caster->_race, caster->faction->magiegebiet); if (rc == NULL) { - log_error("could not find suitable familiar for %s.\n", mage->faction->race->_name); + log_error("could not find suitable familiar for %s.\n", caster->faction->race->_name); return 0; } @@ -554,7 +568,7 @@ static int sp_summon_familiar(castorder * co) int dir, dh; if (coasts == 0) { - cmistake(mage, co->order, 229, MSG_MAGIC); + cmistake(caster, co->order, 229, MSG_MAGIC); return 0; } @@ -573,14 +587,14 @@ static int sp_summon_familiar(castorder * co) } } - msg = msg_message("familiar_name", "unit", mage); - nr_render(msg, mage->faction->locale, zText, sizeof(zText), mage->faction); + msg = msg_message("familiar_name", "unit", caster); + nr_render(msg, caster->faction->locale, zText, sizeof(zText), caster->faction); msg_release(msg); - make_familiar(mage, r, rc, zText); + make_familiar(caster, r, rc, zText); - report_race_skills(rc, zText, sizeof(zText), mage->faction->locale); - ADDMSG(&mage->faction->msgs, msg_message("familiar_describe", - "mage race skills", mage, rc, zText)); + report_race_skills_depr(rc, zText, sizeof(zText), caster->faction->locale); + ADDMSG(&caster->faction->msgs, msg_message("familiar_describe", + "mage race skills", caster, rc, zText)); return cast_level; } @@ -599,7 +613,7 @@ static int sp_summon_familiar(castorder * co) * */ static int sp_destroy_magic(castorder * co) { - unit *mage = co->magician.u; + unit *caster = co_get_caster(co); int cast_level = co->level; double force = co->force; spellparameter *pa = co->par; @@ -622,7 +636,7 @@ static int sp_destroy_magic(castorder * co) /* region *tr = pa->param[0]->data.r; -- farcasting! */ region *tr = co_get_region(co); ap = &tr->attribs; - write_regionname(tr, mage->faction, ts, sizeof(ts)); + write_regionname(tr, caster->faction, ts, sizeof(ts)); break; } case SPP_TEMP: @@ -657,13 +671,13 @@ static int sp_destroy_magic(castorder * co) succ = break_curse(ap, cast_level, force, c); if (succ) { - ADDMSG(&mage->faction->msgs, msg_message("destroy_magic_effect", - "unit region command succ target", mage, mage->region, co->order, succ, + ADDMSG(&caster->faction->msgs, msg_message("destroy_magic_effect", + "unit region command succ target", caster, caster->region, co->order, succ, ts)); } else { - ADDMSG(&mage->faction->msgs, msg_message("destroy_magic_noeffect", - "unit region command", mage, mage->region, co->order)); + ADDMSG(&caster->faction->msgs, msg_message("destroy_magic_noeffect", + "unit region command", caster, caster->region, co->order)); } if (succ < 1) succ = 1; @@ -690,13 +704,15 @@ static int sp_destroy_magic(castorder * co) static int sp_transferaura(castorder * co) { - int aura, gain, multi = 2; - unit *mage = co->magician.u; + int aura, used, multi = 2; + unit *caster = co_get_caster(co); + unit *mage = co_get_magician(co); int cast_level = co->level; spellparameter *pa = co->par; unit *u; - sc_mage *scm_dst, *scm_src = get_mage_depr(mage); + struct sc_mage *scm_dst, *scm_src = get_mage(mage); + assert(scm_src); /* wenn kein Ziel gefunden, Zauber abbrechen */ if (pa->param[0]->flag == TARGET_NOTFOUND) return 0; @@ -709,43 +725,46 @@ static int sp_transferaura(castorder * co) /* Wieviel Transferieren? */ aura = pa->param[1]->data.i; u = pa->param[0]->data.u; - scm_dst = get_mage_depr(u); + scm_dst = get_mage(u); if (scm_dst == NULL) { /* "Zu dieser Einheit kann ich keine Aura uebertragen." */ - cmistake(mage, co->order, 207, MSG_MAGIC); + cmistake(caster, co->order, 207, MSG_MAGIC); return 0; } - else if (scm_src->magietyp == M_TYBIED) { - if (scm_src->magietyp != scm_dst->magietyp) - multi = 3; - } - else if (scm_src->magietyp == M_GRAY) { - if (scm_src->magietyp != scm_dst->magietyp) - multi = 4; - } - else if (scm_dst->magietyp != scm_src->magietyp) { - /* "Zu dieser Einheit kann ich keine Aura uebertragen." */ - cmistake(mage, co->order, 207, MSG_MAGIC); - return 0; + else { + magic_t src = mage_get_type(scm_src); + magic_t dst = mage_get_type(scm_dst); + if (src != dst) { + if (src == M_TYBIED) { + multi = 3; + } + else if (src == M_GRAY) { + multi = 4; + } + else { + /* "Zu dieser Einheit kann ich keine Aura uebertragen." */ + cmistake(caster, co->order, 207, MSG_MAGIC); + return 0; + } + } } if (aura < multi) { /* "Auraangabe fehlerhaft." */ - cmistake(mage, co->order, 208, MSG_MAGIC); + cmistake(caster, co->order, 208, MSG_MAGIC); return 0; } - gain = scm_src->spellpoints; - if (gain > aura) gain = aura; - gain = gain / multi; - scm_src->spellpoints -= gain * multi; - scm_dst->spellpoints += gain; + used = mage_get_spellpoints(scm_src); + if (used > aura) used = aura; + mage_change_spellpoints(scm_src, -used); + mage_change_spellpoints(scm_dst, used / multi); /* sprintf(buf, "%s transferiert %d Aura auf %s", unitname(mage), gain, unitname(u)); */ - ADDMSG(&mage->faction->msgs, msg_message("auratransfer_success", - "unit target aura", mage, u, gain)); + ADDMSG(&caster->faction->msgs, msg_message("auratransfer_success", + "unit target aura", caster, u, used)); return cast_level; } @@ -767,7 +786,7 @@ static int sp_transferaura(castorder * co) static int sp_goodwinds(castorder * co) { region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *caster = co_get_caster(co); int cast_level = co->level; double power = co->force; int duration = cast_level + 1; @@ -784,14 +803,14 @@ static int sp_goodwinds(castorder * co) /* keine Probleme mit C_SHIP_SPEEDUP und C_SHIP_FLYING */ /* NODRIFT bewirkt auch +1 Geschwindigkeit */ - create_curse(mage, &sh->attribs, &ct_nodrift, power, duration, + create_curse(caster, &sh->attribs, &ct_nodrift, power, duration, zero_effect, 0); /* melden, 1x pro Partei */ - freset(mage->faction, FFL_SELECT); + freset(caster->faction, FFL_SELECT); for (u = r->units; u; u = u->next) freset(u->faction, FFL_SELECT); - m = msg_message("wind_effect", "mage ship", mage, sh); + m = msg_message("wind_effect", "mage ship", caster, sh); for (u = r->units; u; u = u->next) { if (u->ship != sh) /* nur den Schiffsbesatzungen! */ continue; @@ -800,8 +819,8 @@ static int sp_goodwinds(castorder * co) fset(u->faction, FFL_SELECT); } } - if (!fval(mage->faction, FFL_SELECT)) { - r_addmessage(r, mage->faction, m); + if (!fval(caster->faction, FFL_SELECT)) { + r_addmessage(r, caster->faction, m); } msg_release(m); @@ -823,22 +842,22 @@ static int sp_goodwinds(castorder * co) static int sp_magicstreet(castorder * co) { region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *caster = co_get_caster(co); if (!fval(r->terrain, LAND_REGION)) { - cmistake(mage, co->order, 186, MSG_MAGIC); + cmistake(caster, co->order, 186, MSG_MAGIC); return 0; } /* wirkt schon in der Zauberrunde! */ - create_curse(mage, &r->attribs, &ct_magicstreet, co->force, + create_curse(caster, &r->attribs, &ct_magicstreet, co->force, co->level + 1, zero_effect, 0); /* melden, 1x pro Partei */ { - message *seen = msg_message("path_effect", "mage region", mage, r); + message *seen = msg_message("path_effect", "mage region", caster, r); message *unseen = msg_message("path_effect", "mage region", (unit *)NULL, r); - report_effect(r, mage, seen, unseen); + report_effect(r, caster, seen, unseen); msg_release(seen); msg_release(unseen); } @@ -864,7 +883,7 @@ static int sp_magicstreet(castorder * co) static int sp_summonent(castorder * co) { region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *caster = co_get_caster(co); int cast_level = co->level; double power = co->force; unit *u; @@ -872,7 +891,7 @@ static int sp_summonent(castorder * co) int ents, p2; if (rtrees(r, 2) == 0) { - cmistake(mage, co->order, 204, MSG_EVENT); + cmistake(caster, co->order, 204, MSG_EVENT); /* nicht ohne baeume */ return 0; } @@ -881,7 +900,7 @@ static int sp_summonent(castorder * co) p2 = (int)(power * power); if (ents > p2) ents = p2; - u = create_unit(r, mage->faction, ents, get_race(RC_TREEMAN), 0, NULL, mage); + u = create_unit(r, caster->faction, ents, get_race(RC_TREEMAN), 0, NULL, caster); a = a_new(&at_unitdissolve); a->data.ca[0] = 2; /* An r->trees. */ @@ -893,9 +912,9 @@ static int sp_summonent(castorder * co) /* melden, 1x pro Partei */ { - message *seen = msg_message("ent_effect", "mage amount", mage, ents); + message *seen = msg_message("ent_effect", "mage amount", caster, ents); message *unseen = msg_message("ent_effect", "mage amount", (unit *)NULL, ents); - report_effect(r, mage, seen, unseen); + report_effect(r, caster, seen, unseen); msg_release(unseen); msg_release(seen); } @@ -920,7 +939,7 @@ static int sp_blessstonecircle(castorder * co) { building *b; region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *caster = co_get_caster(co); int cast_level = co->level; spellparameter *p = co->par; message *msg; @@ -932,20 +951,20 @@ static int sp_blessstonecircle(castorder * co) b = p->param[0]->data.b; if (!is_building_type(b->type, "stonecircle")) { - ADDMSG(&mage->faction->msgs, msg_feedback(mage, co->order, + ADDMSG(&caster->faction->msgs, msg_feedback(caster, co->order, "error_notstonecircle", "building", b)); return 0; } if (!building_finished(b)) { - ADDMSG(&mage->faction->msgs, msg_feedback(mage, co->order, + ADDMSG(&caster->faction->msgs, msg_feedback(caster, co->order, "error_notcomplete", "building", b)); return 0; } b->type = bt_find("blessedstonecircle"); - msg = msg_message("blessedstonecircle_effect", "mage building", mage, b); + msg = msg_message("blessedstonecircle_effect", "mage building", caster, b); add_message(&r->msgs, msg); msg_release(msg); @@ -969,13 +988,13 @@ static int sp_blessstonecircle(castorder * co) static int sp_maelstrom(castorder * co) { region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *caster = co_get_caster(co); int cast_level = co->level; curse *c; int duration = (int)co->force + 1; if (!fval(r->terrain, SEA_REGION)) { - cmistake(mage, co->order, 205, MSG_MAGIC); + cmistake(caster, co->order, 205, MSG_MAGIC); /* nur auf ozean */ return 0; } @@ -983,13 +1002,13 @@ static int sp_maelstrom(castorder * co) /* Attribut auf Region. * Existiert schon ein curse, so wird dieser verstaerkt * (Max(Dauer), Max(Staerke))*/ - c = create_curse(mage, &r->attribs, &ct_maelstrom, co->force, duration, co->force, 0); + c = create_curse(caster, &r->attribs, &ct_maelstrom, co->force, duration, co->force, 0); /* melden, 1x pro Partei */ if (c) { - message *seen = msg_message("maelstrom_effect", "mage", mage); + message *seen = msg_message("maelstrom_effect", "mage", caster); message *unseen = msg_message("maelstrom_effect", "mage", (unit *)NULL); - report_effect(r, mage, seen, unseen); + report_effect(r, caster, seen, unseen); msg_release(seen); msg_release(unseen); } @@ -1012,14 +1031,14 @@ static int sp_mallorn(castorder * co) { region *r = co_get_region(co); int cast_level = co->level; - unit *mage = co->magician.u; + unit *caster = co_get_caster(co); if (!fval(r->terrain, LAND_REGION)) { - cmistake(mage, co->order, 186, MSG_MAGIC); + cmistake(caster, co->order, 186, MSG_MAGIC); return 0; } if (fval(r, RF_MALLORN)) { - cmistake(mage, co->order, 191, MSG_MAGIC); + cmistake(caster, co->order, 191, MSG_MAGIC); return 0; } @@ -1031,9 +1050,9 @@ static int sp_mallorn(castorder * co) /* melden, 1x pro Partei */ { - message *seen = msg_message("mallorn_effect", "mage", mage); + message *seen = msg_message("mallorn_effect", "mage", caster); message *unseen = msg_message("mallorn_effect", "mage", (unit *)NULL); - report_effect(r, mage, seen, unseen); + report_effect(r, caster, seen, unseen); msg_release(seen); msg_release(unseen); } @@ -1056,19 +1075,19 @@ static int sp_mallorn(castorder * co) static int sp_blessedharvest(castorder * co) { region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *caster = co_get_caster(co); int cast_level = co->level; int duration = (int)co->force + 1; /* Attribut auf Region. * Existiert schon ein curse, so wird dieser verstaerkt * (Max(Dauer), Max(Staerke))*/ - if (create_curse(mage, &r->attribs, &ct_blessedharvest, co->force, + if (create_curse(caster, &r->attribs, &ct_blessedharvest, co->force, duration, 1.0, 0)) { const char * effect = co->sp->sname[0]=='b' ? "harvest_effect" : "raindance_effect"; - message *seen = msg_message(effect, "mage", mage); + message *seen = msg_message(effect, "mage", caster); message *unseen = msg_message(effect, "mage", (unit *)NULL); - report_effect(r, mage, seen, unseen); + report_effect(r, caster, seen, unseen); msg_release(seen); msg_release(unseen); } @@ -1093,16 +1112,16 @@ static int sp_hain(castorder * co) { int trees; region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *caster = co_get_caster(co); int cast_level = co->level; double force = co->force; if (!r->land) { - cmistake(mage, co->order, 296, MSG_MAGIC); + cmistake(caster, co->order, 296, MSG_MAGIC); return 0; } if (fval(r, RF_MALLORN)) { - cmistake(mage, co->order, 92, MSG_MAGIC); + cmistake(caster, co->order, 92, MSG_MAGIC); return 0; } @@ -1111,10 +1130,10 @@ static int sp_hain(castorder * co) /* melden, 1x pro Partei */ { - message *seen = msg_message("growtree_effect", "mage amount", mage, trees); + message *seen = msg_message("growtree_effect", "mage amount", caster, trees); message *unseen = msg_message("growtree_effect", "mage amount", (unit *)NULL, trees); - report_effect(r, mage, seen, unseen); + report_effect(r, caster, seen, unseen); msg_release(seen); msg_release(unseen); } @@ -1139,16 +1158,16 @@ static int sp_mallornhain(castorder * co) { int trees; region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *caster = co_get_caster(co); int cast_level = co->level; double force = co->force; if (!r->land) { - cmistake(mage, co->order, 296, MSG_MAGIC); + cmistake(caster, co->order, 296, MSG_MAGIC); return 0; } if (!fval(r, RF_MALLORN)) { - cmistake(mage, co->order, 91, MSG_MAGIC); + cmistake(caster, co->order, 91, MSG_MAGIC); return 0; } @@ -1157,10 +1176,10 @@ static int sp_mallornhain(castorder * co) /* melden, 1x pro Partei */ { - message *seen = msg_message("growtree_effect", "mage amount", mage, trees); + message *seen = msg_message("growtree_effect", "mage amount", caster, trees); message *unseen = msg_message("growtree_effect", "mage amount", (unit *)NULL, trees); - report_effect(r, mage, seen, unseen); + report_effect(r, caster, seen, unseen); msg_release(seen); msg_release(unseen); } @@ -1173,7 +1192,7 @@ static void fumble_ents(const castorder * co) int ents; unit *u; region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *mage = co_get_caster(co); /* int cast_level = co->level; */ double force = co->force; @@ -1239,7 +1258,7 @@ static int sp_rosthauch(castorder * co) int n; int success = 0; region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *caster = co_get_caster(co); int cast_level = co->level; int force = (int)co->force; spellparameter *pa = co->par; @@ -1292,17 +1311,17 @@ static int sp_rosthauch(castorder * co) if (ironweapon > 0) { /* {$mage mage} legt einen Rosthauch auf {target}. {amount} Waffen * wurden vom Rost zerfressen */ - ADDMSG(&mage->faction->msgs, msg_message("rust_effect", - "mage target amount", mage, u, ironweapon)); + ADDMSG(&caster->faction->msgs, msg_message("rust_effect", + "mage target amount", caster, u, ironweapon)); ADDMSG(&u->faction->msgs, msg_message("rust_effect", "mage target amount", - cansee(u->faction, r, mage, 0) ? mage : NULL, u, ironweapon)); + cansee(u->faction, r, caster, 0) ? caster : NULL, u, ironweapon)); success += ironweapon; } else { /* {$mage mage} legt einen Rosthauch auf {target}, doch der * Rosthauch fand keine Nahrung */ - ADDMSG(&mage->faction->msgs, msg_message("rust_fail", "mage target", mage, + ADDMSG(&caster->faction->msgs, msg_message("rust_fail", "mage target", caster, u)); } } @@ -1337,7 +1356,7 @@ static int sp_kaelteschutz(castorder * co) int n, i = 0; int men; region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *caster = co_get_caster(co); int cast_level = co->level; double force = co->force; double effect; @@ -1368,15 +1387,15 @@ static int sp_kaelteschutz(castorder * co) } effect = 1; - create_curse(mage, &u->attribs, &ct_insectfur, (float)cast_level, + create_curse(caster, &u->attribs, &ct_insectfur, (float)cast_level, duration, effect, men); force -= u->number; - ADDMSG(&mage->faction->msgs, msg_message("heat_effect", "mage target", mage, + ADDMSG(&caster->faction->msgs, msg_message("heat_effect", "mage target", caster, u)); - if (u->faction != mage->faction) + if (u->faction != caster->faction) ADDMSG(&u->faction->msgs, msg_message("heat_effect", "mage target", - cansee(u->faction, r, mage, 0) ? mage : NULL, u)); + cansee(u->faction, r, caster, 0) ? caster : NULL, u)); i = cast_level; } /* Erstattung? */ @@ -1401,7 +1420,7 @@ static int sp_kaelteschutz(castorder * co) static int sp_sparkle(castorder * co) { unit *u; - unit *mage = co->magician.u; + unit *caster = co_get_caster(co); int cast_level = co->level; spellparameter *pa = co->par; int duration = cast_level + 1; @@ -1418,13 +1437,13 @@ static int sp_sparkle(castorder * co) u = pa->param[0]->data.u; effect = (float)(rng_int() % 0xffffff); - create_curse(mage, &u->attribs, &ct_sparkle, (float)cast_level, + create_curse(caster, &u->attribs, &ct_sparkle, (float)cast_level, duration, effect, u->number); - ADDMSG(&mage->faction->msgs, msg_message("sparkle_effect", "mage target", - mage, u)); - if (u->faction != mage->faction) { - ADDMSG(&u->faction->msgs, msg_message("sparkle_effect", "mage target", mage, + ADDMSG(&caster->faction->msgs, msg_message("sparkle_effect", "mage target", + caster, u)); + if (u->faction != caster->faction) { + ADDMSG(&u->faction->msgs, msg_message("sparkle_effect", "mage target", caster, u)); } @@ -1463,7 +1482,7 @@ static int sp_create_irongolem(castorder * co) unit *u2; attrib *a; region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *caster = co_get_caster(co); int cast_level = co->level; double force = co->force; int number = lovar(force * 8 * RESOURCE_QUANTITY); @@ -1479,11 +1498,11 @@ static int sp_create_irongolem(castorder * co) } if (r->terrain == newterrain(T_SWAMP)) { - cmistake(mage, co->order, 188, MSG_MAGIC); + cmistake(caster, co->order, 188, MSG_MAGIC); return 0; } - u2 = create_unit(r, mage->faction, number, golem_rc, 0, NULL, mage); + u2 = create_unit(r, caster->faction, number, golem_rc, 0, NULL, caster); set_level(u2, SK_ARMORER, 1); set_level(u2, SK_WEAPONSMITH, 1); @@ -1493,10 +1512,10 @@ static int sp_create_irongolem(castorder * co) a->data.ca[1] = IRONGOLEM_CRUMBLE; a_add(&u2->attribs, a); - ADDMSG(&mage->faction->msgs, + ADDMSG(&caster->faction->msgs, msg_message("magiccreate_effect", "region command unit amount object", - mage->region, co->order, mage, number, - LOC(mage->faction->locale, rc_name_s(golem_rc, (u2->number == 1) ? NAME_SINGULAR : NAME_PLURAL)))); + caster->region, co->order, caster, number, + LOC(caster->faction->locale, rc_name_s(golem_rc, (u2->number == 1) ? NAME_SINGULAR : NAME_PLURAL)))); return cast_level; } @@ -1533,7 +1552,7 @@ static int sp_create_stonegolem(castorder * co) unit *u2; attrib *a; region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *caster = co_get_caster(co); int cast_level = co->level; int number = lovar(co->force * 5 * RESOURCE_QUANTITY); static int cache; @@ -1546,12 +1565,12 @@ static int sp_create_stonegolem(castorder * co) number = 1; if (r->terrain == newterrain(T_SWAMP)) { - cmistake(mage, co->order, 188, MSG_MAGIC); + cmistake(caster, co->order, 188, MSG_MAGIC); return 0; } u2 = - create_unit(r, mage->faction, number, golem_rc, 0, NULL, mage); + create_unit(r, caster->faction, number, golem_rc, 0, NULL, caster); set_level(u2, SK_ROAD_BUILDING, 1); set_level(u2, SK_BUILDING, 1); @@ -1560,10 +1579,10 @@ static int sp_create_stonegolem(castorder * co) a->data.ca[1] = STONEGOLEM_CRUMBLE; a_add(&u2->attribs, a); - ADDMSG(&mage->faction->msgs, + ADDMSG(&caster->faction->msgs, msg_message("magiccreate_effect", "region command unit amount object", - mage->region, co->order, mage, number, - LOC(mage->faction->locale, rc_name_s(golem_rc, (u2->number == 1) ? NAME_SINGULAR : NAME_PLURAL)))); + caster->region, co->order, caster, number, + LOC(caster->faction->locale, rc_name_s(golem_rc, (u2->number == 1) ? NAME_SINGULAR : NAME_PLURAL)))); return cast_level; } @@ -1601,14 +1620,14 @@ static int sp_great_drought(castorder * co) unit *u; bool terraform = false; region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *caster = co_get_caster(co); int cast_level = co->level; double force = co->force; int duration = 2; double effect; if (fval(r->terrain, SEA_REGION)) { - cmistake(mage, co->order, 189, MSG_MAGIC); + cmistake(caster, co->order, 189, MSG_MAGIC); /* TODO: vielleicht einen netten Patzer hier? */ return 0; } @@ -1622,7 +1641,7 @@ static int sp_great_drought(castorder * co) /* Arbeitslohn = 1/4 */ effect = 4.0; /* curses: higher is stronger */ - create_curse(mage, &r->attribs, &ct_drought, force, duration, effect, + create_curse(caster, &r->attribs, &ct_drought, force, duration, effect, 0); /* terraforming */ @@ -1685,14 +1704,14 @@ static int sp_great_drought(castorder * co) else { mtype = "drought_effect_3"; } - msg = msg_message(mtype, "mage region", mage, r); + msg = msg_message(mtype, "mage region", caster, r); add_message(&r->msgs, msg); msg_release(msg); } else { /* possible that all units here get killed so better to inform with a global * message */ - message *msg = msg_message("drought_effect_4", "mage region", mage, r); + message *msg = msg_message("drought_effect_4", "mage region", caster, r); for (u = r->units; u; u = u->next) freset(u->faction, FFL_SELECT); for (u = r->units; u; u = u->next) { @@ -1701,8 +1720,8 @@ static int sp_great_drought(castorder * co) add_message(&u->faction->msgs, msg); } } - if (!fval(mage->faction, FFL_SELECT)) { - add_message(&mage->faction->msgs, msg); + if (!fval(caster->faction, FFL_SELECT)) { + add_message(&caster->faction->msgs, msg); } msg_release(msg); } @@ -1728,7 +1747,7 @@ static int sp_great_drought(castorder * co) static int sp_treewalkenter(castorder * co) { region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *caster = co_get_caster(co); spellparameter *pa = co->par; double power = co->force; int cast_level = co->level; @@ -1738,19 +1757,19 @@ static int sp_treewalkenter(castorder * co) int erfolg = 0; if (getplane(r) != 0) { - cmistake(mage, co->order, 190, MSG_MAGIC); + cmistake(caster, co->order, 190, MSG_MAGIC); return 0; } if (!r_isforest(r)) { - cmistake(mage, co->order, 191, MSG_MAGIC); + cmistake(caster, co->order, 191, MSG_MAGIC); return 0; } rt = r_standard_to_astral(r); if (rt == NULL || is_cursed(rt->attribs, &ct_astralblock) || fval(rt->terrain, FORBIDDEN_REGION)) { - ADDMSG(&mage->faction->msgs, msg_feedback(mage, co->order, + ADDMSG(&caster->faction->msgs, msg_feedback(caster, co->order, "spellfail_astralblock", "")); return 0; } @@ -1766,8 +1785,8 @@ static int sp_treewalkenter(castorder * co) continue; } - if (!ucontact(u, mage)) { - ADDMSG(&mage->faction->msgs, msg_feedback(mage, co->order, + if (!ucontact(u, caster)) { + ADDMSG(&caster->faction->msgs, msg_feedback(caster, co->order, "feedback_no_contact", "target", u)); } else { @@ -1776,13 +1795,13 @@ static int sp_treewalkenter(castorder * co) unit *u2; if (!can_survive(u, rt)) { - cmistake(mage, co->order, 231, MSG_MAGIC); + cmistake(caster, co->order, 231, MSG_MAGIC); continue; } w = weight(u); if (remaining_cap - w < 0) { - ADDMSG(&mage->faction->msgs, msg_feedback(mage, co->order, + ADDMSG(&caster->faction->msgs, msg_feedback(caster, co->order, "fail_tooheavy", "target", u)); continue; } @@ -1854,18 +1873,18 @@ static int sp_treewalkexit(castorder * co) int n; int erfolg = 0; region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *caster = co_get_caster(co); double power = co->force; spellparameter *pa = co->par; int cast_level = co->level; if (!is_astral(r)) { - ADDMSG(&mage->faction->msgs, msg_feedback(mage, co->order, + ADDMSG(&caster->faction->msgs, msg_feedback(caster, co->order, "spellfail_astralonly", "")); return 0; } if (is_cursed(r->attribs, &ct_astralblock)) { - ADDMSG(&mage->faction->msgs, msg_feedback(mage, co->order, + ADDMSG(&caster->faction->msgs, msg_feedback(caster, co->order, "spellfail_astralblock", "")); return 0; } @@ -1873,7 +1892,7 @@ static int sp_treewalkexit(castorder * co) remaining_cap = (int)(power * 500); if (pa->param[0]->typ != SPP_REGION) { - report_failure(mage, co->order); + report_failure(caster, co->order); return 0; } @@ -1897,12 +1916,12 @@ static int sp_treewalkexit(castorder * co) free_regionlist(rl); if (!rt) { - cmistake(mage, co->order, 195, MSG_MAGIC); + cmistake(caster, co->order, 195, MSG_MAGIC); return 0; } if (!r_isforest(rt)) { - cmistake(mage, co->order, 196, MSG_MAGIC); + cmistake(caster, co->order, 196, MSG_MAGIC); return 0; } @@ -1914,17 +1933,17 @@ static int sp_treewalkexit(castorder * co) u = pa->param[n]->data.u; - if (!ucontact(u, mage)) { - ADDMSG(&mage->faction->msgs, msg_feedback(mage, co->order, + if (!ucontact(u, caster)) { + ADDMSG(&caster->faction->msgs, msg_feedback(caster, co->order, "feedback_no_contact", "target", u)); } else { int w = weight(u); if (!can_survive(u, rt)) { - cmistake(mage, co->order, 231, MSG_MAGIC); + cmistake(caster, co->order, 231, MSG_MAGIC); } else if (remaining_cap - w < 0) { - ADDMSG(&mage->faction->msgs, msg_feedback(mage, co->order, + ADDMSG(&caster->faction->msgs, msg_feedback(caster, co->order, "fail_tooheavy", "target", u)); } else { @@ -1990,14 +2009,14 @@ static int sp_treewalkexit(castorder * co) static int sp_holyground(castorder * co) { region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *caster = co_get_caster(co); int cast_level = co->level; double power = co->force; - message *msg = msg_message("sp_holyground_effect", "mage region", mage, r); - report_spell(mage, r, msg); + message *msg = msg_message("sp_holyground_effect", "mage region", caster, r); + report_spell(caster, r, msg); msg_release(msg); - create_curse(mage, &r->attribs, &ct_holyground, power * power, 1, zero_effect, 0); + create_curse(caster, &r->attribs, &ct_holyground, power * power, 1, zero_effect, 0); a_removeall(&r->attribs, &at_deathcount); @@ -2022,38 +2041,38 @@ static int sp_homestone(castorder * co) unit *u; curse *c; region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *caster = co_get_caster(co); int cast_level = co->level; double force = co->force; double effect; message *msg; - if (!mage->building || !is_building_type(mage->building->type, "castle")) { - cmistake(mage, co->order, 197, MSG_MAGIC); + if (!caster->building || !is_building_type(caster->building->type, "castle")) { + cmistake(caster, co->order, 197, MSG_MAGIC); return 0; } - c = create_curse(mage, &mage->building->attribs, &ct_magicwalls, + c = create_curse(caster, &caster->building->attribs, &ct_magicwalls, force * force, 1, zero_effect, 0); if (c == NULL) { - cmistake(mage, co->order, 206, MSG_MAGIC); + cmistake(caster, co->order, 206, MSG_MAGIC); return 0; } /* Magieresistenz der Burg erhoeht sich um 50% */ effect = 50.0F; - c = create_curse(mage, &mage->building->attribs, + c = create_curse(caster, &caster->building->attribs, &ct_magicresistance, force * force, 1, effect, 0); c_setflag(c, CURSE_NOAGE); /* melden, 1x pro Partei in der Burg */ for (u = r->units; u; u = u->next) freset(u->faction, FFL_SELECT); - msg = msg_message("homestone_effect", "mage building", mage, mage->building); + msg = msg_message("homestone_effect", "mage building", caster, caster->building); for (u = r->units; u; u = u->next) { if (!fval(u->faction, FFL_SELECT)) { fset(u->faction, FFL_SELECT); - if (u->building == mage->building) { + if (u->building == caster->building) { r_addmessage(r, u->faction, msg); } } @@ -2080,21 +2099,21 @@ static int sp_drought(castorder * co) { curse *c; region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *caster = co_get_caster(co); int cast_level = co->level; double power = co->force; int duration = (int)power + 1; message *msg; if (fval(r->terrain, SEA_REGION)) { - cmistake(mage, co->order, 189, MSG_MAGIC); + cmistake(caster, co->order, 189, MSG_MAGIC); /* TODO: vielleicht einen netten Patzer hier? */ return 0; } /* melden, 1x pro Partei */ - msg = msg_message("sp_drought_effect", "mage region", mage, r); - report_spell(mage, r, msg); + msg = msg_message("sp_drought_effect", "mage region", caster, r); + report_spell(caster, r, msg); msg_release(msg); /* Wenn schon Duerre herrscht, dann setzen wir nur den Power-Level @@ -2114,7 +2133,7 @@ static int sp_drought(castorder * co) rsettrees(r, 0, rtrees(r, 0) / 2); rsethorses(r, rhorses(r) / 2); - create_curse(mage, &r->attribs, &ct_drought, power, duration, effect, + create_curse(caster, &r->attribs, &ct_drought, power, duration, effect, 0); } return cast_level; @@ -2143,18 +2162,18 @@ static int sp_ironkeeper(castorder * co) { unit *keeper; region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *caster = co_get_caster(co); int cast_level = co->level; message *msg; if (r->terrain != newterrain(T_MOUNTAIN) && r->terrain != newterrain(T_GLACIER)) { - report_failure(mage, co->order); + report_failure(caster, co->order); return 0; } keeper = - create_unit(r, mage->faction, 1, get_race(RC_IRONKEEPER), 0, NULL, mage); + create_unit(r, caster->faction, 1, get_race(RC_IRONKEEPER), 0, NULL, caster); /*keeper->age = cast_level + 2; */ unit_setstatus(keeper, ST_AVOID); /* kaempft nicht */ @@ -2171,7 +2190,7 @@ static int sp_ironkeeper(castorder * co) tkill)); } - msg = msg_message("summon_effect", "mage amount race", mage, 1, u_race(keeper)); + msg = msg_message("summon_effect", "mage amount race", caster, 1, u_race(keeper)); r_addmessage(r, NULL, msg); msg_release(msg); @@ -2202,14 +2221,14 @@ static int sp_stormwinds(castorder * co) unit *u; int erfolg = 0; region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *caster = co_get_caster(co); double power = co->force; spellparameter *pa = co->par; int n, force = (int)power; message *m = NULL; /* melden vorbereiten */ - freset(mage->faction, FFL_SELECT); + freset(caster->faction, FFL_SELECT); for (u = r->units; u; u = u->next) freset(u->faction, FFL_SELECT); @@ -2225,18 +2244,18 @@ static int sp_stormwinds(castorder * co) /* mit C_SHIP_NODRIFT haben wir kein Problem */ if (is_cursed(sh->attribs, &ct_flyingship)) { - ADDMSG(&mage->faction->msgs, msg_feedback(mage, co->order, + ADDMSG(&caster->faction->msgs, msg_feedback(caster, co->order, "error_spell_on_flying_ship", "ship", sh)) continue; } if (is_cursed(sh->attribs, &ct_shipspeedup)) { - ADDMSG(&mage->faction->msgs, msg_feedback(mage, co->order, + ADDMSG(&caster->faction->msgs, msg_feedback(caster, co->order, "error_spell_on_ship_already", "ship", sh)) continue; } /* Duration = 1, nur diese Runde */ - create_curse(mage, &sh->attribs, &ct_stormwind, power, 1, + create_curse(caster, &sh->attribs, &ct_stormwind, power, 1, zero_effect, 0); /* Da der Spruch nur diese Runde wirkt wird er nie im Report * erscheinen */ @@ -2252,17 +2271,17 @@ static int sp_stormwinds(castorder * co) } } if (erfolg < pa->length) { - ADDMSG(&mage->faction->msgs, msg_message("stormwinds_reduced", - "unit ships maxships", mage, erfolg, pa->length)); + ADDMSG(&caster->faction->msgs, msg_message("stormwinds_reduced", + "unit ships maxships", caster, erfolg, pa->length)); } /* melden, 1x pro Partei auf Schiff und fuer den Magier */ - fset(mage->faction, FFL_SELECT); + fset(caster->faction, FFL_SELECT); for (u = r->units; u; u = u->next) { if (fval(u->faction, FFL_SELECT)) { freset(u->faction, FFL_SELECT); if (erfolg > 0) { if (!m) { - m = msg_message("stormwinds_effect", "unit", mage); + m = msg_message("stormwinds_effect", "unit", caster); } r_addmessage(r, u->faction, m); } @@ -2289,7 +2308,7 @@ static int sp_stormwinds(castorder * co) static int sp_earthquake(castorder * co) { region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *caster = co_get_caster(co); int cast_level = co->level; message *msg; building **blist = &r->buildings; @@ -2299,7 +2318,7 @@ static int sp_earthquake(castorder * co) if (burg->size != 0 && !is_cursed(burg->attribs, &ct_magicwalls)) { /* Magieresistenz */ - if (!target_resists_magic(mage, burg, TYP_BUILDING, 0)) { + if (!target_resists_magic(caster, burg, TYP_BUILDING, 0)) { int kaputt = burg->size / 4; if (kaputt > 10 * cast_level) kaputt = 10 * cast_level; if (kaputt < 1) kaputt = 1; @@ -2315,7 +2334,7 @@ static int sp_earthquake(castorder * co) } /* melden, 1x pro Partei */ - msg = msg_message("earthquake_effect", "mage region", mage, r); + msg = msg_message("earthquake_effect", "mage region", caster, r); r_addmessage(r, NULL, msg); msg_release(msg); return cast_level; @@ -2324,13 +2343,12 @@ static int sp_earthquake(castorder * co) /* ------------------------------------------------------------- */ /* CHAOS / M_DRAIG / Draig */ /* ------------------------------------------------------------- */ -void patzer_peasantmob(const castorder * co) +static void patzer_peasantmob(const castorder * co) { unit *u; attrib *a; region *r; - unit *mage = co->magician.u; - + unit *mage = co_get_magician(co); r = mage->region->land ? mage->region : co_get_region(co); if (r->land) { @@ -2348,7 +2366,7 @@ void patzer_peasantmob(const castorder * co) create_unit(r, f, n, get_race(RC_PEASANT), 0, LOC(f->locale, "angry_mob"), NULL); fset(u, UFL_ISNEW); - addlist(&u->orders, create_order(K_GUARD, lang, NULL)); + unit_addorder(u, create_order(K_GUARD, lang, NULL)); set_order(&u->thisorder, default_order(lang)); a = a_new(&at_unitdissolve); a->data.ca[0] = 1; /* An rpeasants(r). */ @@ -2395,7 +2413,7 @@ static int sp_forest_fire(castorder * co) region *nr; direction_t i; region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *caster = co_get_caster(co); int cast_level = co->level; double probability; double percentage = (rng_int() % 8 + 1) * 0.1; /* 10 - 80% */ @@ -2405,7 +2423,7 @@ static int sp_forest_fire(castorder * co) int destroyed = (int)(rtrees(r, 2) * percentage); if (destroyed < 1) { - cmistake(mage, co->order, 198, MSG_MAGIC); + cmistake(caster, co->order, 198, MSG_MAGIC); return 0; } @@ -2417,10 +2435,10 @@ static int sp_forest_fire(castorder * co) for (u = r->units; u; u = u->next) freset(u->faction, FFL_SELECT); msg = - msg_message("forestfire_effect", "mage region amount", mage, r, + msg_message("forestfire_effect", "mage region amount", caster, r, destroyed + vernichtet_schoesslinge); r_addmessage(r, NULL, msg); - add_message(&mage->faction->msgs, msg); + add_message(&caster->faction->msgs, msg); msg_release(msg); for (i = 0; i < MAXDIRECTIONS; i++) { @@ -2447,7 +2465,7 @@ static int sp_forest_fire(castorder * co) r, nr, destroyed + vernichtet_schoesslinge); add_message(&r->msgs, m); - add_message(&mage->faction->msgs, m); + add_message(&caster->faction->msgs, m); msg_release(m); rsettrees(nr, 2, rtrees(nr, 2) - destroyed); @@ -2479,7 +2497,7 @@ static int sp_fumblecurse(castorder * co) { unit *target; int duration; - unit *mage = co->magician.u; + unit *caster = co_get_caster(co); int cast_level = co->level; double force = co->force; double effect; @@ -2500,10 +2518,10 @@ static int sp_fumblecurse(castorder * co) ++duration; effect = force / 2; - c = create_curse(mage, &target->attribs, &ct_fumble, + c = create_curse(caster, &target->attribs, &ct_fumble, force, duration, effect, 0); if (c == NULL) { - report_failure(mage, co->order); + report_failure(caster, co->order); return 0; } @@ -2513,9 +2531,9 @@ static int sp_fumblecurse(castorder * co) return cast_level; } -void patzer_fumblecurse(const castorder * co) +static void patzer_fumblecurse(const castorder * co) { - unit *mage = co->magician.u; + unit *mage = co_get_magician(co); int cast_level = co->level; double force = co->force; int duration = (cast_level / 2) + 1; @@ -2553,7 +2571,7 @@ void patzer_fumblecurse(const castorder * co) static int sp_summondragon(castorder * co) { region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *caster = co_get_caster(co); unit *u; int cast_level = co->level; double power = co->force; @@ -2567,7 +2585,7 @@ static int sp_summondragon(castorder * co) if (r->terrain != newterrain(T_SWAMP) && r->terrain != newterrain(T_DESERT) && r->terrain != newterrain(T_GLACIER)) { - report_failure(mage, co->order); + report_failure(caster, co->order); return 0; } @@ -2614,8 +2632,8 @@ static int sp_summondragon(castorder * co) } } - ADDMSG(&mage->faction->msgs, msg_message("summondragon", - "unit region command target", mage, mage->region, co->order, r)); + ADDMSG(&caster->faction->msgs, msg_message("summondragon", + "unit region command target", caster, caster->region, co->order, r)); free_regionlist(rl); return cast_level; @@ -2626,24 +2644,24 @@ static int sp_firewall(castorder * co) connection *b; wall_data *fd; region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *caster = co_get_caster(co); int cast_level = co->level; double force = co->force; spellparameter *pa = co->par; direction_t dir; region *r2; - dir = get_direction(pa->param[0]->data.xs, mage->faction->locale); + dir = get_direction(pa->param[0]->data.xs, caster->faction->locale); if (dir < MAXDIRECTIONS && dir != NODIRECTION) { r2 = rconnect(r, dir); } else { - report_failure(mage, co->order); + report_failure(caster, co->order); return 0; } if (!r2 || r2 == r) { - report_failure(mage, co->order); + report_failure(caster, co->order); return 0; } @@ -2657,7 +2675,7 @@ static int sp_firewall(castorder * co) b = new_border(&bt_firewall, r, r2); fd = (wall_data *)b->data.v; fd->force = (int)(force / 2 + 0.5); - fd->mage = mage; + fd->mage = caster; fd->active = false; fd->countdown = cast_level + 1; } @@ -2670,9 +2688,9 @@ static int sp_firewall(castorder * co) /* melden, 1x pro Partei */ { - message *seen = msg_message("firewall_effect", "mage region", mage, r); + message *seen = msg_message("firewall_effect", "mage region", caster, r); message *unseen = msg_message("firewall_effect", "mage region", (unit *)NULL, r); - report_effect(r, mage, seen, unseen); + report_effect(r, caster, seen, unseen); msg_release(seen); msg_release(unseen); } @@ -2717,7 +2735,7 @@ static const race *unholy_race(const race *rc) { static int sp_unholypower(castorder * co) { region * r = co_get_region(co); - unit *mage = co->magician.u; + unit *caster = co_get_caster(co); int cast_level = co->level; spellparameter *pa = co->par; int i; @@ -2738,7 +2756,7 @@ static int sp_unholypower(castorder * co) target_race = unholy_race(u_race(u)); if (!target_race) { - cmistake(mage, co->order, 284, MSG_MAGIC); + cmistake(caster, co->order, 284, MSG_MAGIC); continue; } /* Untote heilen nicht, darum den neuen Untoten maximale hp geben @@ -2751,7 +2769,7 @@ static int sp_unholypower(castorder * co) u_setrace(u, target_race); u->hp = unit_max_hp(u) * u->number - wounds; ADDMSG(&r->msgs, msg_message("unholypower_effect", - "mage target race", mage, u, target_race)); + "mage target race", caster, u, target_race)); } else { unit *un; @@ -2762,7 +2780,7 @@ static int sp_unholypower(castorder * co) * waere es, eine solche Konstruktion irgendwie zu kapseln. */ if (fval(u, UFL_LOCKED) || fval(u, UFL_HUNGER) || is_cursed(u->attribs, &ct_slavery)) { - cmistake(mage, co->order, 74, MSG_MAGIC); + cmistake(caster, co->order, 74, MSG_MAGIC); continue; } /* Verletzungsanteil der transferierten Personen berechnen */ @@ -2772,7 +2790,7 @@ static int sp_unholypower(castorder * co) transfermen(u, un, n); un->hp = unit_max_hp(un) * n - wounds; ADDMSG(&r->msgs, msg_message("unholypower_limitedeffect", - "mage target race amount", mage, u, target_race, n)); + "mage target race amount", caster, u, target_race, n)); n = 0; } } @@ -2899,7 +2917,7 @@ static int dc_read_compat(variant *var, void *target, gamedata *data) static int sp_deathcloud(castorder * co) { region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *caster = co_get_caster(co); attrib *a = r->attribs; unit *u; @@ -2907,7 +2925,7 @@ static int sp_deathcloud(castorder * co) if (a->type == &at_curse) { curse *c = a->data.v; if (c->type == &ct_deathcloud) { - report_failure(mage, co->order); + report_failure(caster, co->order); return 0; } a = a->next; @@ -2916,7 +2934,7 @@ static int sp_deathcloud(castorder * co) a = a->nexttype; } - mk_deathcloud(mage, r, co->force, co->level); + mk_deathcloud(caster, r, co->force, co->level); /* melden, 1x pro Partei */ for (u = r->units; u; u = u->next) @@ -2925,13 +2943,13 @@ static int sp_deathcloud(castorder * co) if (!fval(u->faction, FFL_SELECT)) { fset(u->faction, FFL_SELECT); ADDMSG(&u->faction->msgs, msg_message("deathcloud_effect", - "mage region", cansee(u->faction, r, mage, 0) ? mage : NULL, r)); + "mage region", cansee(u->faction, r, caster, 0) ? caster : NULL, r)); } } - if (!fval(mage->faction, FFL_SELECT)) { - ADDMSG(&mage->faction->msgs, msg_message("deathcloud_effect", - "mage region", mage, r)); + if (!fval(caster->faction, FFL_SELECT)) { + ADDMSG(&caster->faction->msgs, msg_message("deathcloud_effect", + "mage region", caster, r)); } return co->level; @@ -2939,7 +2957,7 @@ static int sp_deathcloud(castorder * co) static void patzer_deathcloud(const castorder * co) { - unit *mage = co->magician.u; + unit *mage = co_get_magician(co); int hp = (mage->hp - 2); change_hitpoints(mage, -(rng_int() % hp)); @@ -2963,13 +2981,13 @@ static void patzer_deathcloud(const castorder * co) static int sp_plague(castorder * co) { region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *caster = co_get_caster(co); int cast_level = co->level; plagues(r); - ADDMSG(&mage->faction->msgs, msg_message("plague_spell", - "region mage", r, mage)); + ADDMSG(&caster->faction->msgs, msg_message("plague_spell", + "region mage", r, caster)); return cast_level; } @@ -2992,22 +3010,22 @@ static int sp_plague(castorder * co) static int sp_summonshadow(castorder * co) { region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *caster = co_get_caster(co); int cast_level = co->level; double force = co->force; unit *u; int val, number = (int)(force * force); - u = create_unit(r, mage->faction, number, get_race(RC_SHADOW), 0, NULL, mage); + u = create_unit(r, caster->faction, number, get_race(RC_SHADOW), 0, NULL, caster); /* Bekommen Tarnung = (Magie+Tarnung)/2 und Wahrnehmung 1. */ - val = get_level(mage, SK_MAGIC) + get_level(mage, SK_STEALTH); + val = get_level(caster, SK_MAGIC) + get_level(caster, SK_STEALTH); set_level(u, SK_STEALTH, val); set_level(u, SK_PERCEPTION, 1); - ADDMSG(&mage->faction->msgs, msg_message("summonshadow_effect", - "mage number", mage, number)); + ADDMSG(&caster->faction->msgs, msg_message("summonshadow_effect", + "mage number", caster, number)); return cast_level; } @@ -3033,20 +3051,20 @@ static int sp_summonshadowlords(castorder * co) { unit *u; region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *caster = co_get_caster(co); int cast_level = co->level; double force = co->force; int amount = (int)(force * force); - u = create_unit(r, mage->faction, amount, get_race(RC_SHADOWLORD), 0, - NULL, mage); + u = create_unit(r, caster->faction, amount, get_race(RC_SHADOWLORD), 0, + NULL, caster); /* Bekommen Tarnung = Magie und Wahrnehmung 5. */ - set_level(u, SK_STEALTH, get_level(mage, SK_MAGIC)); + set_level(u, SK_STEALTH, get_level(caster, SK_MAGIC)); set_level(u, SK_PERCEPTION, 5); - ADDMSG(&mage->faction->msgs, msg_message("summon_effect", "mage amount race", - mage, amount, u_race(u))); + ADDMSG(&caster->faction->msgs, msg_message("summon_effect", "mage amount race", + caster, amount, u_race(u))); return cast_level; } @@ -3066,12 +3084,12 @@ static int sp_chaossuction(castorder * co) { region *rt; region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *caster = co_get_caster(co); int cast_level = co->level; if (rplane(r)) { /* Der Zauber funktioniert nur in der materiellen Welt. */ - cmistake(mage, co->order, 190, MSG_MAGIC); + cmistake(caster, co->order, 190, MSG_MAGIC); return 0; } @@ -3079,11 +3097,11 @@ static int sp_chaossuction(castorder * co) if (rt == NULL || fval(rt->terrain, FORBIDDEN_REGION)) { /* Hier gibt es keine Verbindung zur astralen Welt. */ - cmistake(mage, co->order, 216, MSG_MAGIC); + cmistake(caster, co->order, 216, MSG_MAGIC); return 0; } else if (is_cursed(rt->attribs, &ct_astralblock)) { - ADDMSG(&mage->faction->msgs, msg_feedback(mage, co->order, + ADDMSG(&caster->faction->msgs, msg_feedback(caster, co->order, "spellfail_astralblock", "")); return 0; } @@ -3093,7 +3111,7 @@ static int sp_chaossuction(castorder * co) create_special_direction(rt, r, 2, "vortex_desc", "vortex", false); new_border(&bt_chaosgate, r, rt); - add_message(&r->msgs, msg_message("chaosgate_effect_1", "mage", mage)); + add_message(&r->msgs, msg_message("chaosgate_effect_1", "mage", caster)); add_message(&rt->msgs, msg_message("chaosgate_effect_2", "")); return cast_level; } @@ -3122,30 +3140,30 @@ static int sp_chaossuction(castorder * co) static int sp_magicboost(castorder * co) { curse *c; - unit *mage = co->magician.u; + unit *caster = co_get_caster(co); int cast_level = co->level; double power = co->force; double effect; trigger *tsummon; /* fehler, wenn schon ein boost */ - if (is_cursed(mage->attribs, &ct_magicboost)) { - report_failure(mage, co->order); + if (is_cursed(caster->attribs, &ct_magicboost)) { + report_failure(caster, co->order); return 0; } effect = 6; - create_curse(mage, &mage->attribs, &ct_magicboost, power, 10, effect, 1); + create_curse(caster, &caster->attribs, &ct_magicboost, power, 10, effect, 1); /* one aura boost with 200% aura now: */ effect = 200; - c = create_curse(mage, &mage->attribs, &ct_auraboost, power, 4, effect, 1); + c = create_curse(caster, &caster->attribs, &ct_auraboost, power, 4, effect, 1); /* and one aura boost with 50% aura in 5 weeks: */ - tsummon = trigger_createcurse(mage, mage, &ct_auraboost, power, 6, 50, 1); - add_trigger(&mage->attribs, "timer", trigger_timeout(5, tsummon)); + tsummon = trigger_createcurse(caster, caster, &ct_auraboost, power, 6, 50, 1); + add_trigger(&caster->attribs, "timer", trigger_timeout(5, tsummon)); - ADDMSG(&mage->faction->msgs, msg_message("magicboost_effect", - "unit region command", c->magician, mage->region, co->order)); + ADDMSG(&caster->faction->msgs, msg_message("magicboost_effect", + "unit region command", c->magician, caster->region, co->order)); return cast_level; } @@ -3171,14 +3189,14 @@ static int sp_magicboost(castorder * co) */ static int sp_bloodsacrifice(castorder * co) { - unit *mage = co->magician.u; + unit *caster = co_get_caster(co); int cast_level = co->level; int aura; - int skill = effskill(mage, SK_MAGIC, 0); + int skill = effskill(caster, SK_MAGIC, 0); int hp = (int)(co->force * 8); if (hp <= 0) { - report_failure(mage, co->order); + report_failure(caster, co->order); return 0; } @@ -3199,17 +3217,17 @@ static int sp_bloodsacrifice(castorder * co) } if (aura <= 0) { - report_failure(mage, co->order); + report_failure(caster, co->order); return 0; } /* sicherheitshalber gibs hier einen HP gratis. sonst schaffen es * garantiert ne ganze reihe von leuten ihren Magier damit umzubringen */ - mage->hp++; - change_spellpoints(mage, aura); - ADDMSG(&mage->faction->msgs, + caster->hp++; + change_spellpoints(caster, aura); + ADDMSG(&caster->faction->msgs, msg_message("sp_bloodsacrifice_effect", - "unit region command amount", mage, mage->region, co->order, aura)); + "unit region command amount", caster, caster->region, co->order, aura)); return cast_level; } @@ -3248,7 +3266,7 @@ static int sp_summonundead(castorder * co) int undead, dc; unit *u; region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *mage = co_get_caster(co); int cast_level = co->level; int force = (int)(co->force * 10); const race *race = get_race(RC_SKELETON); @@ -3305,7 +3323,7 @@ static int sp_auraleak(castorder * co) double lost; unit *u; region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *mage = co_get_caster(co); int cast_level = co->level; message *msg; @@ -3348,7 +3366,7 @@ static int sp_analysesong_obj(castorder * co) { int obj; region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *mage = co_get_caster(co); int cast_level = co->level; double force = co->force; spellparameter *pa = co->par; @@ -3397,7 +3415,7 @@ static int sp_analysesong_obj(castorder * co) static int sp_analysesong_unit(castorder * co) { unit *u; - unit *mage = co->magician.u; + unit *mage = co_get_caster(co); int cast_level = co->level; double force = co->force; spellparameter *pa = co->par; @@ -3482,7 +3500,7 @@ static int sp_charmingsong(castorder * co) unit *target; int duration; skill_t i; - unit *mage = co->magician.u; + unit *mage = co_get_caster(co); int cast_level = co->level; double force = co->force; spellparameter *pa = co->par; @@ -3571,7 +3589,7 @@ static int sp_charmingsong(castorder * co) static int sp_song_resistmagic(castorder * co) { region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *mage = co_get_caster(co); int cast_level = co->level; double force = co->force; int duration = (int)force + 1; @@ -3600,7 +3618,7 @@ static int sp_song_resistmagic(castorder * co) static int sp_song_susceptmagic(castorder * co) { region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *mage = co_get_caster(co); int cast_level = co->level; double force = co->force; int duration = (int)force + 1; @@ -3629,7 +3647,7 @@ static int sp_rallypeasantmob(castorder * co) unit *u, *un; int erfolg = 0; region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *mage = co_get_caster(co); int cast_level = co->level; message *msg; curse *c; @@ -3682,7 +3700,7 @@ static int sp_raisepeasantmob(castorder * co) int n; int anteil; region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *mage = co_get_caster(co); int rp, cast_level = co->level; double force = co->force; int duration = (int)force + 1; @@ -3738,7 +3756,7 @@ static int sp_migranten(castorder * co) { unit *target; region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *mage = co_get_caster(co); int cast_level = co->level; spellparameter *pa = co->par; @@ -3772,7 +3790,7 @@ static int sp_migranten(castorder * co) return 0; } /* maximal Stufe Personen */ - if (target->number > cast_level || target->number > max_spellpoints(r, mage)) { + if (target->number > cast_level || target->number > max_spellpoints_depr(r, mage)) { ADDMSG(&mage->faction->msgs, msg_feedback(mage, co->order, "spellfail_toomanytargets", "")); return 0; @@ -3806,7 +3824,7 @@ static int sp_song_of_peace(castorder * co) { unit *u; region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *mage = co_get_caster(co); int cast_level = co->level; double force = co->force; int duration = 2 + lovar(force / 2); @@ -3855,7 +3873,7 @@ static int sp_generous(castorder * co) { unit *u; region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *mage = co_get_caster(co); int cast_level = co->level; double force = co->force; int duration = (int)force + 1; @@ -3913,7 +3931,7 @@ static int sp_recruit(castorder * co) region *r = co_get_region(co); int num, maxp = rpeasants(r); double n; - unit *mage = co->magician.u; + unit *mage = co_get_caster(co); int cast_level = co->level; double force = co->force; faction *f = mage->faction; @@ -3968,7 +3986,7 @@ static int sp_bigrecruit(castorder * co) unit *u; region *r = co_get_region(co); int n, maxp = rpeasants(r); - unit *mage = co->magician.u; + unit *mage = co_get_caster(co); int cast_level = co->level; double force = co->force; faction *f = mage->faction; @@ -4023,7 +4041,7 @@ static int sp_pump(castorder * co) unit *u, *target; region *rt; bool see = false; - unit *mage = co->magician.u; + unit *mage = co_get_caster(co); spellparameter *pa = co->par; int cast_level = co->level; @@ -4084,7 +4102,7 @@ static int sp_seduce(castorder * co) const resource_type *rsilver = get_resourcetype(R_SILVER); unit *target; item **itmp, *items = NULL; - unit *u, *mage = co->magician.u; + unit *u, *caster = co_get_caster(co); spellparameter *pa = co->par; int cast_level = co->level; double force = co->force; @@ -4097,15 +4115,15 @@ static int sp_seduce(castorder * co) target = pa->param[0]->data.u; /* Zieleinheit */ if (fval(u_race(target), RCF_UNDEAD)) { - ADDMSG(&mage->faction->msgs, msg_feedback(mage, co->order, + ADDMSG(&caster->faction->msgs, msg_feedback(caster, co->order, "spellfail_noundead", "")); return 0; } - u = mage; - if (mage->region != target->region) { + u = caster; + if (caster->region != target->region) { for (u = target->region->units; u; u = u->next) { - if (u->faction == mage->faction) { + if (u->faction == caster->faction) { break; } } @@ -4143,7 +4161,7 @@ static int sp_seduce(castorder * co) if (items) { if (u) { - ADDMSG(&mage->faction->msgs, msg_message("seduce_effect_0", "mage unit items", + ADDMSG(&caster->faction->msgs, msg_message("seduce_effect_0", "mage unit items", u, target, items)); i_freeall(&items); } @@ -4173,7 +4191,7 @@ static int sp_calm_monster(castorder * co) { curse *c; unit *target; - unit *mage = co->magician.u; + unit *caster = co_get_caster(co); spellparameter *pa = co->par; int cast_level = co->level; double force = co->force; @@ -4187,21 +4205,21 @@ static int sp_calm_monster(castorder * co) target = pa->param[0]->data.u; /* Zieleinheit */ if (fval(u_race(target), RCF_UNDEAD)) { - ADDMSG(&mage->faction->msgs, msg_feedback(mage, co->order, + ADDMSG(&caster->faction->msgs, msg_feedback(caster, co->order, "spellfail_noundead", "")); return 0; } - effect = mage->faction->subscription; - c = create_curse(mage, &target->attribs, &ct_calmmonster, force, + effect = caster->faction->uid; + c = create_curse(caster, &target->attribs, &ct_calmmonster, force, (int)force, effect, 0); if (c == NULL) { - report_failure(mage, co->order); + report_failure(caster, co->order); return 0; } - msg = msg_message("calm_effect", "mage unit", mage, target); - r_addmessage(mage->region, mage->faction, msg); + msg = msg_message("calm_effect", "mage unit", caster, target); + r_addmessage(caster->region, caster->faction, msg); msg_release(msg); return cast_level; } @@ -4225,13 +4243,13 @@ static int sp_headache(castorder * co) skill *smax = NULL; int i; unit *target; - unit *mage = co->magician.u; + unit *caster = co_get_caster(co); spellparameter *pa = co->par; int cast_level = co->level; message *msg; /* Macht alle nachfolgenden Zauber doppelt so teuer */ - countspells(mage, 1); + countspells(caster, 1); target = pa->param[0]->data.u; /* Zieleinheit */ @@ -4255,8 +4273,8 @@ static int sp_headache(castorder * co) } set_order(&target->thisorder, NULL); - msg = msg_message("hangover_effect_0", "mage unit", mage, target); - r_addmessage(mage->region, mage->faction, msg); + msg = msg_message("hangover_effect_0", "mage unit", caster, target); + r_addmessage(caster->region, caster->faction, msg); msg_release(msg); msg = msg_message("hangover_effect_1", "unit", target); @@ -4284,13 +4302,13 @@ static int sp_raisepeasants(castorder * co) unit *u2; attrib *a; region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *caster = co_get_caster(co); int rp = rpeasants(r), cast_level = co->level; double power = co->force; message *msg; if (rp == 0) { - ADDMSG(&mage->faction->msgs, msg_feedback(mage, co->order, + ADDMSG(&caster->faction->msgs, msg_feedback(caster, co->order, "error_nopeasants", "")); return 0; } @@ -4299,8 +4317,8 @@ static int sp_raisepeasants(castorder * co) rsetpeasants(r, rp - bauern); u2 = - create_unit(r, mage->faction, bauern, get_race(RC_PEASANT), 0, - LOC(mage->faction->locale, "furious_mob"), mage); + create_unit(r, caster->faction, bauern, get_race(RC_PEASANT), 0, + LOC(caster->faction->locale, "furious_mob"), caster); fset(u2, UFL_LOCKED); if (rule_stealth_anon()) { @@ -4313,11 +4331,11 @@ static int sp_raisepeasants(castorder * co) a_add(&u2->attribs, a); msg = - msg_message("sp_raisepeasants_effect", "mage region amount", mage, r, + msg_message("sp_raisepeasants_effect", "mage region amount", caster, r, u2->number); r_addmessage(r, NULL, msg); - if (mage->region != r) { - add_message(&mage->faction->msgs, msg); + if (caster->region != r) { + add_message(&caster->faction->msgs, msg); } msg_release(msg); @@ -4338,7 +4356,7 @@ static int sp_raisepeasants(castorder * co) static int sp_depression(castorder * co) { region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *mage = co_get_caster(co); int cast_level = co->level; double force = co->force; int duration = (int)force + 1; @@ -4372,7 +4390,7 @@ static int sp_depression(castorder * co) int sp_puttorest(castorder * co) { region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *mage = co_get_caster(co); int dead = deathcount(r); int laid_to_rest = dice((int)(co->force * 2), 100); message *seen = msg_message("puttorest", "mage", mage); @@ -4404,7 +4422,7 @@ int sp_icastle(castorder * co) building *b; const building_type *type; region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *mage = co_get_caster(co); int cast_level = co->level; double power = co->force; spellparameter *pa = co->par; @@ -4472,7 +4490,7 @@ int sp_illusionary_shapeshift(castorder * co) { unit *u; const race *rc; - unit *mage = co->magician.u; + unit *mage = co_get_caster(co); int cast_level = co->level; double power = co->force; spellparameter *pa = co->par; @@ -4529,7 +4547,7 @@ int sp_illusionary_shapeshift(castorder * co) int sp_analysedream(castorder * co) { unit *u; - unit *mage = co->magician.u; + unit *mage = co_get_caster(co); int cast_level = co->level; spellparameter *pa = co->par; @@ -4551,7 +4569,7 @@ int sp_analysedream(castorder * co) static int sp_gbdreams(castorder * co, int effect) { int duration; - unit *mage = co->magician.u; + unit *mage = co_get_caster(co); int cast_level = co->level; double power = co->force; region *r = co_get_region(co); @@ -4623,7 +4641,7 @@ int sp_clonecopy(castorder * co) unit *clone; region *r = co_get_region(co); region *target_region = co_get_region(co); - unit *mage = co->magician.u; + unit *mage = co_get_caster(co); int cast_level = co->level; message *msg; char name[NAMESIZE]; @@ -4655,7 +4673,7 @@ int sp_dreamreading(castorder * co) { unit *u; region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *mage = co_get_caster(co); int cast_level = co->level; spellparameter *pa = co->par; double power = co->force; @@ -4702,7 +4720,7 @@ int sp_dreamreading(castorder * co) int sp_sweetdreams(castorder * co) { region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *mage = co_get_caster(co); int cast_level = co->level; double power = co->force; spellparameter *pa = co->par; @@ -4752,7 +4770,7 @@ int sp_sweetdreams(castorder * co) int sp_disturbingdreams(castorder * co) { region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *mage = co_get_caster(co); int cast_level = co->level; double power = co->force; int duration = 1 + (int)(power / 6); @@ -4840,7 +4858,7 @@ int sp_analysemagic(castorder * co) int sp_itemcloak(castorder * co) { unit *target; - unit *mage = co->magician.u; + unit *mage = co_get_caster(co); spellparameter *pa = co->par; int cast_level = co->level; double power = co->force; @@ -4881,7 +4899,7 @@ int sp_resist_magic_bonus(castorder * co) unit *u; int n, m; int duration = 6; - unit *mage = co->magician.u; + unit *mage = co_get_caster(co); int cast_level = co->level; double power = co->force; spellparameter *pa = co->par; @@ -4938,7 +4956,7 @@ int sp_enterastral(castorder * co) int remaining_cap; int n, w; region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *mage = co_get_caster(co); int cast_level = co->level; double power = co->force; spellparameter *pa = co->par; @@ -5053,7 +5071,7 @@ int sp_pullastral(castorder * co) int remaining_cap; int n, w; region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *mage = co_get_caster(co); int cast_level = co->level; double power = co->force; spellparameter *pa = co->par; @@ -5195,7 +5213,7 @@ int sp_leaveastral(castorder * co) int remaining_cap; int n, w; region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *mage = co_get_caster(co); int cast_level = co->level; double power = co->force; spellparameter *pa = co->par; @@ -5321,7 +5339,7 @@ int sp_leaveastral(castorder * co) int sp_fetchastral(castorder * co) { int n; - unit *mage = co->magician.u; + unit *mage = co_get_caster(co); int cast_level = 0; spellparameter *pa = co->par; double power = co->force; @@ -5371,6 +5389,7 @@ int sp_fetchastral(castorder * co) ro = u->region; } + assert(ro); cast_level = co->level; /* at least one unit could have been teleported */ if (is_cursed(ro->attribs, &ct_astralblock)) { ADDMSG(&mage->faction->msgs, msg_feedback(mage, co->order, @@ -5458,7 +5477,7 @@ int sp_showastral(castorder * co) int c = 0; region_list *rl, *rl2; region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *mage = co_get_caster(co); int cast_level = co->level; double power = co->force; @@ -5544,7 +5563,7 @@ int sp_viewreality(castorder * co) { region_list *rl, *rl2; region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *mage = co_get_caster(co); int cast_level = co->level; message *m; @@ -5581,7 +5600,7 @@ int sp_disruptastral(castorder * co) region *rt; unit *u; region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *mage = co_get_caster(co); int cast_level = co->level; double power = co->force; int duration = (int)(power / 3) + 1; @@ -5645,8 +5664,9 @@ int sp_disruptastral(castorder * co) int c = rng_int() % inhab_regions; /* Zufaellige Zielregion suchen */ - while (c-- != 0) + while (c-- != 0) { trl2 = trl2->next; + } tr = trl2->data; if (!is_magic_resistant(mage, u, 0) && can_survive(u, tr)) { @@ -5688,7 +5708,7 @@ static int sp_eternizewall(castorder * co) curse *c; building *b; region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *mage = co_get_caster(co); int cast_level = co->level; double power = co->force; spellparameter *pa = co->par; @@ -5753,7 +5773,8 @@ int sp_permtransfer(castorder * co) { int aura, i; unit *tu; - unit *mage = co->magician.u; + unit *caster = co_get_caster(co); + unit *mage = co_get_magician(co); int cast_level = co->level; spellparameter *pa = co->par; const spell *sp = co->sp; @@ -5774,27 +5795,26 @@ int sp_permtransfer(castorder * co) if (!is_mage(tu)) { /* sprintf(buf, "%s in %s: 'ZAUBER %s': Einheit ist kein Magier." , unitname(mage), regionname(mage->region, mage->faction),sa->strings[0]); */ - cmistake(mage, co->order, 214, MSG_MAGIC); + cmistake(caster, co->order, 214, MSG_MAGIC); return 0; } - i = get_spellpoints(mage) - spellcost(mage, sp); + i = get_spellpoints(mage) - auracost(mage, sp); if (aura > i) aura = i; change_maxspellpoints(mage, -aura); change_spellpoints(mage, -aura); - if (get_mage_depr(tu)->magietyp == get_mage_depr(mage)->magietyp) { + if (unit_get_magic(tu) == unit_get_magic(mage)) { change_maxspellpoints(tu, aura / 2); } else { change_maxspellpoints(tu, aura / 3); } - msg = - msg_message("sp_permtransfer_effect", "mage target amount", mage, tu, aura); - add_message(&mage->faction->msgs, msg); - if (tu->faction != mage->faction) { + msg = msg_message("sp_permtransfer_effect", "mage target amount", mage, tu, aura); + add_message(&caster->faction->msgs, msg); + if (tu->faction != caster->faction) { add_message(&tu->faction->msgs, msg); } msg_release(msg); @@ -5812,7 +5832,7 @@ int sp_movecastle(castorder * co) region *target_region; unit *u, *unext; region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *mage = co_get_caster(co); int cast_level = co->level; spellparameter *pa = co->par; message *msg; @@ -5895,10 +5915,12 @@ int sp_stealaura(castorder * co) { int taura; unit *u; - unit *mage = co->magician.u; + unit *mage = co_get_magician(co); + unit *caster = co_get_caster(co); int cast_level = co->level; double power = co->force; spellparameter *pa = co->par; + struct sc_mage *scm; /* wenn kein Ziel gefunden, Zauber abbrechen */ if (pa->param[0]->flag == TARGET_NOTFOUND) @@ -5907,30 +5929,31 @@ int sp_stealaura(castorder * co) /* Zieleinheit */ u = pa->param[0]->data.u; - if (!get_mage_depr(u)) { - ADDMSG(&mage->faction->msgs, msg_message("stealaura_fail", "unit target", - mage, u)); + scm = get_mage(u); + if (!scm) { + ADDMSG(&caster->faction->msgs, msg_message("stealaura_fail", "unit target", + caster, u)); ADDMSG(&u->faction->msgs, msg_message("stealaura_fail_detect", "unit", u)); return 0; } - taura = (get_mage_depr(u)->spellpoints * (rng_int() % (int)(3 * power) + 1)) / 100; + taura = (mage_get_spellpoints(scm) * (rng_int() % (int)(3 * power) + 1)) / 100; if (taura > 0) { - get_mage_depr(u)->spellpoints -= taura; - get_mage_depr(mage)->spellpoints += taura; + mage_change_spellpoints(scm, -taura); + change_spellpoints(mage, taura); /* sprintf(buf, "%s entzieht %s %d Aura.", unitname(mage), unitname(u), taura); */ - ADDMSG(&mage->faction->msgs, msg_message("stealaura_success", - "mage target aura", mage, u, taura)); + ADDMSG(&caster->faction->msgs, msg_message("stealaura_success", + "mage target aura", caster, u, taura)); /* sprintf(buf, "%s fuehlt seine magischen Kraefte schwinden und verliert %d " "Aura.", unitname(u), taura); */ ADDMSG(&u->faction->msgs, msg_message("stealaura_detect", "unit aura", u, taura)); } else { - ADDMSG(&mage->faction->msgs, msg_message("stealaura_fail", "unit target", - mage, u)); + ADDMSG(&caster->faction->msgs, msg_message("stealaura_fail", "unit target", + caster, u)); ADDMSG(&u->faction->msgs, msg_message("stealaura_fail_detect", "unit", u)); } return cast_level; @@ -5965,7 +5988,7 @@ int sp_antimagiczone(castorder * co) double power; double effect; region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *mage = co_get_caster(co); int cast_level = co->level; double force = co->force; int duration = (int)force + 1; @@ -6022,7 +6045,7 @@ int sp_antimagiczone(castorder * co) static int sp_magicrunes(castorder * co) { int duration; - unit *mage = co->magician.u; + unit *mage = co_get_caster(co); int cast_level = co->level; double force = co->force; spellparameter *pa = co->par; @@ -6082,7 +6105,7 @@ int sp_speed2(castorder * co) { int n, maxmen, used = 0, dur, men; unit *u; - unit *mage = co->magician.u; + unit *mage = co_get_caster(co); int cast_level = co->level; double force = co->force; spellparameter *pa = co->par; @@ -6142,7 +6165,7 @@ int sp_break_curse(castorder * co) int obj; curse *c; region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *mage = co_get_caster(co); int cast_level = co->level; double force = co->force; spellparameter *pa = co->par; @@ -6299,7 +6322,7 @@ static int sp_babbler(castorder * co) { unit *target; region *r = co_get_region(co); - unit *mage = co->magician.u; + unit *mage = co_get_caster(co); int cast_level = co->level; spellparameter *pa = co->par; message *msg; @@ -6346,7 +6369,7 @@ static int sp_babbler(castorder * co) static int sp_readmind(castorder * co) { unit *target; - unit *mage = co->magician.u; + unit *mage = co_get_caster(co); int cast_level = co->level; spellparameter *pa = co->par; diff --git a/src/spells.test.c b/src/spells.test.c index 1e024ef7f..6ee4a305c 100644 --- a/src/spells.test.c +++ b/src/spells.test.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/spells/borders.c b/src/spells/borders.c index c30726641..c0e51a9b1 100644 --- a/src/spells/borders.c +++ b/src/spells/borders.c @@ -13,8 +13,8 @@ #include #include -#include -#include +#include +#include #include #include #include @@ -79,7 +79,7 @@ const curse_type ct_firewall = { static void wall_init(connection * b) { - wall_data *fd = (wall_data *)calloc(sizeof(wall_data), 1); + wall_data *fd = (wall_data *)calloc(1, sizeof(wall_data)); fd->countdown = -1; /* infinite */ b->data.v = fd; } diff --git a/src/spells/combatspells.c b/src/spells/combatspells.c index 06a78c4f4..21b33e7bf 100644 --- a/src/spells/combatspells.c +++ b/src/spells/combatspells.c @@ -36,7 +36,7 @@ #include /* util includes */ -#include +#include #include #include #include @@ -956,7 +956,7 @@ int sp_hero(struct castorder * co) if (df) { if (!(df->person[dt.index].flags & FL_COURAGE)) { - df->person[dt.index].defence += df_bonus; + df->person[dt.index].defense += df_bonus; df->person[dt.index].flags = df->person[dt.index].flags | FL_COURAGE; targets++; --force; @@ -1005,7 +1005,7 @@ int sp_berserk(struct castorder * co) if (df) { if (!(df->person[dt.index].flags & FL_COURAGE)) { df->person[dt.index].attack += at_bonus; - df->person[dt.index].defence -= df_malus; + df->person[dt.index].defense -= df_malus; df->person[dt.index].flags = df->person[dt.index].flags | FL_COURAGE; targets++; --force; @@ -1064,7 +1064,7 @@ int sp_frighten(struct castorder * co) } if (!is_magic_resistant(mage, df->unit, 0)) { df->person[dt.index].attack -= at_malus; - df->person[dt.index].defence -= df_malus; + df->person[dt.index].defense -= df_malus; targets++; } --force; @@ -1109,7 +1109,7 @@ int sp_tiredsoldiers(struct castorder * co) if (!(df->person[t.index].flags & FL_TIRED)) { if (!is_magic_resistant(mage, df->unit, 0)) { df->person[t.index].flags = df->person[t.index].flags | FL_TIRED; - df->person[t.index].defence -= 2; + df->person[t.index].defense -= 2; ++n; } } @@ -1539,12 +1539,7 @@ int sp_undeadhero(struct castorder * co) /* new units gets some stats from old unit */ - if (du->display) { - unit_setinfo(u, du->display); - } - else { - unit_setinfo(u, NULL); - } + unit_setinfo(u, unit_getinfo(du)); unit_setstatus(u, du->status); setguard(u, false); for (ilist = &du->items; *ilist;) { diff --git a/src/spells/flyingship.c b/src/spells/flyingship.c index e23f6906b..4dc186dc5 100644 --- a/src/spells/flyingship.c +++ b/src/spells/flyingship.c @@ -11,7 +11,7 @@ #include #include -#include +#include #include @@ -38,7 +38,7 @@ int sp_flying_ship(castorder * co) ship *sh; unit *u; region *r; - unit *mage; + unit *caster; int cast_level; double power; spellparameter *pa; @@ -47,7 +47,7 @@ int sp_flying_ship(castorder * co) assert(co); r = co_get_region(co); - mage = co->magician.u; + caster = co_get_caster(co); cast_level = co->level; power = co->force; pa = co->par; @@ -57,22 +57,22 @@ int sp_flying_ship(castorder * co) return 0; sh = pa->param[0]->data.sh; if (sh->type->construction->maxsize > 50) { - ADDMSG(&mage->faction->msgs, msg_feedback(mage, co->order, + ADDMSG(&caster->faction->msgs, msg_feedback(caster, co->order, "error_flying_ship_too_big", "ship", sh)); return 0; } /* Duration = 1, nur diese Runde */ - cno = levitate_ship(sh, mage, power, 1); + cno = levitate_ship(sh, caster, power, 1); if (cno == 0) { if (is_cursed(sh->attribs, &ct_flyingship)) { /* Auf dem Schiff befindet liegt bereits so ein Zauber. */ - cmistake(mage, co->order, 211, MSG_MAGIC); + cmistake(caster, co->order, 211, MSG_MAGIC); } else if (is_cursed(sh->attribs, &ct_shipspeedup)) { /* Es ist zu gefaehrlich, ein sturmgepeitschtes Schiff fliegen zu lassen. */ - cmistake(mage, co->order, 210, MSG_MAGIC); + cmistake(caster, co->order, 210, MSG_MAGIC); } return 0; } @@ -86,7 +86,7 @@ int sp_flying_ship(castorder * co) if (!(u->faction->flags & FFL_SELECT)) { u->faction->flags |= FFL_SELECT; if (!m) { - m = msg_message("flying_ship_result", "mage ship", mage, sh); + m = msg_message("flying_ship_result", "mage ship", caster, sh); } add_message(&u->faction->msgs, m); } diff --git a/src/spells/magicresistance.test.c b/src/spells/magicresistance.test.c index cbfdeb4af..390134c56 100644 --- a/src/spells/magicresistance.test.c +++ b/src/spells/magicresistance.test.c @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include "spells.h" diff --git a/src/spells/unitcurse.c b/src/spells/unitcurse.c index a99eb082c..d0b381050 100644 --- a/src/spells/unitcurse.c +++ b/src/spells/unitcurse.c @@ -23,7 +23,7 @@ #include /* util includes */ -#include +#include #include #include #include diff --git a/src/spy.c b/src/spy.c index ae70f4db8..c0d4d614c 100644 --- a/src/spy.c +++ b/src/spy.c @@ -27,6 +27,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "study.h" /* kernel includes */ +#include #include #include #include @@ -44,8 +45,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include /* util includes */ -#include #include +#include #include #include #include @@ -66,16 +67,16 @@ void spy_message(int spy, const unit * u, const unit * target) { char status[32]; - report_status(target, u->faction->locale, status, sizeof(status)); + report_status_depr(target, u->faction->locale, status, sizeof(status)); ADDMSG(&u->faction->msgs, msg_message("spyreport", "spy target status", u, target, status)); if (spy > 20) { - sc_mage *mage = get_mage_depr(target); + magic_t mtype = unit_get_magic(target); /* for mages, spells and magic school */ - if (mage) { + if (mtype != M_GRAY) { ADDMSG(&u->faction->msgs, msg_message("spyreport_mage", "spy target type", u, - target, magic_school[mage->magietyp])); + target, magic_school[mtype])); } } if (spy > 6) { @@ -137,10 +138,6 @@ int spy_cmd(unit * u, struct order *ord) msg_feedback(u, u->thisorder, "feedback_unit_not_found", "")); return 0; } - if (!can_contact(r, u, target)) { - cmistake(u, u->thisorder, 24, MSG_EVENT); - return 0; - } if (effskill(u, SK_SPY, 0) < 1) { cmistake(u, u->thisorder, 39, MSG_EVENT); return 0; diff --git a/src/spy.test.c b/src/spy.test.c index 0224698a0..e5a7ec628 100644 --- a/src/spy.test.c +++ b/src/spy.test.c @@ -11,9 +11,11 @@ #include #include #include -#include +#include + #include #include +#include "util/param.h" #include #include @@ -198,17 +200,17 @@ static void test_setstealth_cmd(CuTest *tc) { test_setup(); u = test_create_unit(test_create_faction(NULL), test_create_plain(0, 0)); lang = u->faction->locale; - u->flags = UFL_ANON_FACTION | UFL_SIEGE; + u->flags = UFL_ANON_FACTION | UFL_DEFENDER; u->thisorder = create_order(K_SETSTEALTH, lang, "%s %s", LOC(lang, parameters[P_FACTION]), LOC(lang, parameters[P_NOT])); setstealth_cmd(u, u->thisorder); - CuAssertIntEquals(tc, UFL_SIEGE, u->flags); + CuAssertIntEquals(tc, UFL_DEFENDER, u->flags); free_order(u->thisorder); u->thisorder = create_order(K_SETSTEALTH, lang, "%s", LOC(lang, parameters[P_FACTION])); setstealth_cmd(u, u->thisorder); - CuAssertIntEquals(tc, UFL_SIEGE | UFL_ANON_FACTION, u->flags); + CuAssertIntEquals(tc, UFL_DEFENDER | UFL_ANON_FACTION, u->flags); test_teardown(); } @@ -270,7 +272,7 @@ static void test_sabotage_other_success(CuTest *tc) { assert(ord); set_level(u2, SK_SPY, 1); CuAssertIntEquals(tc, 0, sabotage_cmd(u2, ord)); - CuAssertPtrEquals(tc, 0, r->ships); + CuAssertPtrEquals(tc, NULL, r->ships); free_order(ord); test_teardown(); } diff --git a/src/steal.c b/src/steal.c index 68a4239ec..8a390c8fb 100644 --- a/src/steal.c +++ b/src/steal.c @@ -188,10 +188,6 @@ void steal_cmd(unit * u, struct order *ord, econ_request ** stealorders) } assert(u->region == u2->region); - if (!can_contact(r, u, u2)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error60", "")); - return; - } effsk = effskill(u, SK_STEALTH, 0); n = effsk - max_skill(r, f, SK_PERCEPTION); diff --git a/src/study.c b/src/study.c index 738c591d7..977e8a7eb 100644 --- a/src/study.c +++ b/src/study.c @@ -32,6 +32,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include +#include #include #include #include @@ -46,10 +47,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include /* util includes */ -#include #include #include #include +#include #include #include #include @@ -419,15 +420,16 @@ int teach_cmd(unit * teacher, struct order *ord) if (sk == SK_MAGIC) { /* ist der Magier schon spezialisiert, so versteht er nur noch * Lehrer seines Gebietes */ - sc_mage *mage1 = get_mage_depr(teacher); - sc_mage *mage2 = get_mage_depr(scholar); - if (mage2 && mage1 && mage2->magietyp != M_GRAY - && mage1->magietyp != mage2->magietyp) { - if (feedback) { - ADDMSG(&teacher->faction->msgs, msg_feedback(teacher, ord, - "error_different_magic", "target", scholar)); + magic_t mage2 = unit_get_magic(scholar); + if (mage2 != M_GRAY) { + magic_t mage1 = unit_get_magic(teacher); + if (mage1 != mage2) { + if (feedback) { + ADDMSG(&teacher->faction->msgs, msg_feedback(teacher, ord, + "error_different_magic", "target", scholar)); + } + continue; } - continue; } } sk_academy = sk; @@ -621,7 +623,7 @@ int study_cmd(unit * u, order * ord) } if (sk == SK_MAGIC) { - magic_t mtyp; + magic_t mtype; if (u->number > 1) { cmistake(u, ord, 106, MSG_MAGIC); return -1; @@ -629,7 +631,7 @@ int study_cmd(unit * u, order * ord) if (is_familiar(u)) { /* Vertraute zaehlen nicht zu den Magiern einer Partei, * koennen aber nur Graue Magie lernen */ - mtyp = M_GRAY; + mtype = M_GRAY; } else if (!has_skill(u, SK_MAGIC)) { int mmax = skill_limit(u->faction, SK_MAGIC); @@ -639,24 +641,24 @@ int study_cmd(unit * u, order * ord) "amount", mmax)); return -1; } - mtyp = getmagicskill(u->faction->locale); - if (mtyp == M_NONE || mtyp == M_GRAY) { + mtype = getmagicskill(u->faction->locale); + if (mtype == M_NONE || mtype == M_GRAY) { /* wurde kein Magiegebiet angegeben, wird davon * ausgegangen, dass das normal gelernt werden soll */ if (u->faction->magiegebiet != 0) { - mtyp = u->faction->magiegebiet; + mtype = u->faction->magiegebiet; } else { /* Es wurde kein Magiegebiet angegeben und die Partei * hat noch keins gewaehlt. */ - mtyp = getmagicskill(u->faction->locale); - if (mtyp == M_NONE) { + mtype = getmagicskill(u->faction->locale); + if (mtype == M_NONE) { cmistake(u, ord, 178, MSG_MAGIC); return -1; } } } - if (mtyp != u->faction->magiegebiet) { + if (mtype != u->faction->magiegebiet) { /* Es wurde versucht, ein anderes Magiegebiet zu lernen * als das der Partei */ if (u->faction->magiegebiet != 0) { @@ -666,25 +668,25 @@ int study_cmd(unit * u, order * ord) else { /* Lernt zum ersten mal Magie und legt damit das * Magiegebiet der Partei fest */ - u->faction->magiegebiet = mtyp; + u->faction->magiegebiet = mtype; } } - create_mage(u, mtyp); + create_mage(u, mtype); } else { /* ist schon ein Magier und kein Vertrauter */ if (u->faction->magiegebiet == 0) { /* die Partei hat noch kein Magiegebiet gewaehlt. */ - mtyp = getmagicskill(u->faction->locale); - if (mtyp == M_NONE) { - mtyp = getmagicskill(u->faction->locale); - if (mtyp == M_NONE) { + mtype = getmagicskill(u->faction->locale); + if (mtype == M_NONE) { + mtype = getmagicskill(u->faction->locale); + if (mtype == M_NONE) { cmistake(u, ord, 178, MSG_MAGIC); return -1; } } /* Legt damit das Magiegebiet der Partei fest */ - u->faction->magiegebiet = mtyp; + u->faction->magiegebiet = mtype; } } } @@ -783,13 +785,7 @@ int study_cmd(unit * u, order * ord) show_potions(f, skill); } } - else if (sk == SK_MAGIC) { - sc_mage *mage = get_mage_depr(u); - if (!mage) { - mage = create_mage(u, u->faction->magiegebiet); - } - } - init_order_depr(NULL); + init_order(NULL, NULL); return 0; } diff --git a/src/study.h b/src/study.h index f85508dec..c1d44ed7b 100644 --- a/src/study.h +++ b/src/study.h @@ -31,6 +31,7 @@ extern "C" { #define STUDYDAYS 30 #define TEACHNUMBER 10 +#define TEACHDIFFERENCE 2 typedef struct teaching_info { struct selist *teachers; diff --git a/src/study.test.c b/src/study.test.c index 679615203..446b442bb 100644 --- a/src/study.test.c +++ b/src/study.test.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include @@ -429,9 +429,9 @@ static void test_study_magic(CuTest *tc) { CuAssertIntEquals(tc, 0, study_cmd(u, u->thisorder)); CuAssertIntEquals(tc, M_GWYRRD, f->magiegebiet); CuAssertIntEquals(tc, 0, i_get(u->items, itype)); - CuAssertPtrNotNull(tc, get_mage_depr(u)); + CuAssertPtrNotNull(tc, get_mage(u)); CuAssertPtrEquals(tc, NULL, test_find_messagetype(f->msgs, "error65")); - CuAssertIntEquals(tc, M_GWYRRD, get_mage_depr(u)->magietyp); + CuAssertIntEquals(tc, M_GWYRRD, unit_get_magic(u)); test_teardown(); } @@ -643,7 +643,6 @@ static void test_teach_many_to_one(CuTest *tc) { static void test_teach_message(CuTest *tc) { unit *u, *u1, *u2; attrib *a; - ally *al; teaching_info *teach; setup_study(); @@ -655,8 +654,7 @@ static void test_teach_message(CuTest *tc) { set_level(u1, SK_CROSSBOW, TEACHDIFFERENCE); u1->thisorder = create_order(K_TEACH, u->faction->locale, itoa36(u->no)); u2 = test_create_unit(test_create_faction(NULL), u->region); - al = ally_add(&u->faction->allies, u2->faction); - al->status = HELP_GUARD; + ally_set(&u->faction->allies, u2->faction, HELP_GUARD); set_level(u2, SK_CROSSBOW, TEACHDIFFERENCE); u2->thisorder = create_order(K_TEACH, u->faction->locale, itoa36(u->no)); CuAssertTrue(tc, !alliedunit(u, u1->faction, HELP_GUARD)); diff --git a/src/test_eressea.c b/src/test_eressea.c index 13a638e3b..fc5c49d1c 100644 --- a/src/test_eressea.c +++ b/src/test_eressea.c @@ -1,12 +1,12 @@ #include #include #include -#include #include #include #include #include #include +#include #include #include @@ -81,6 +81,7 @@ int RunAllTests(int argc, char *argv[]) ADD_SUITE(functions); ADD_SUITE(gamedata); ADD_SUITE(language); + ADD_SUITE(order_parser); ADD_SUITE(parser); ADD_SUITE(password); ADD_SUITE(umlaut); @@ -124,6 +125,7 @@ int RunAllTests(int argc, char *argv[]) ADD_SUITE(automate); ADD_SUITE(battle); ADD_SUITE(calendar); + ADD_SUITE(contact); ADD_SUITE(creport); ADD_SUITE(donations); ADD_SUITE(economy); @@ -137,7 +139,6 @@ int RunAllTests(int argc, char *argv[]) ADD_SUITE(monsters); ADD_SUITE(move); ADD_SUITE(names); - ADD_SUITE(orderdb); ADD_SUITE(orderfile); ADD_SUITE(otherfaction); ADD_SUITE(piracy); @@ -159,6 +160,7 @@ int RunAllTests(int argc, char *argv[]) CuSuite *summary = CuSuiteNew(); int fail_count; game_init(); + bcrypt_workfactor = 4; while (suites) { suite *s = suites->next; RunTests(suites->csuite, suites->name); diff --git a/src/tests.c b/src/tests.c index 6c6ce7b58..22c18ef9c 100644 --- a/src/tests.c +++ b/src/tests.c @@ -1,11 +1,10 @@ #include #include "tests.h" -#include "keyword.h" #include "prefix.h" #include "reports.h" -#include "kernel/calendar.h" #include "vortex.h" +#include "kernel/calendar.h" #include #include #include @@ -13,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -23,11 +23,14 @@ #include #include #include + #include +#include "util/keyword.h" #include #include #include #include +#include "util/param.h" #include #include @@ -146,7 +149,9 @@ struct locale * test_create_locale(void) { locale_setstring(loc, combatstatus[i], combatstatus[i] + 7); } for (i = 0; i != MAXKEYWORDS; ++i) { - locale_setstring(loc, mkname("keyword", keywords[i]), keywords[i]); + if (keywords[i]) { + locale_setstring(loc, mkname("keyword", keywords[i]), keywords[i]); + } } for (i = 0; i != MAXPARAMS; ++i) { locale_setstring(loc, parameters[i], parameters[i]); @@ -163,7 +168,7 @@ struct locale * test_create_locale(void) { struct faction *test_create_faction(const struct race *rc) { struct locale * loc = test_create_locale(); - faction *f = addfaction("nobody@eressea.de", NULL, rc ? rc : test_create_race("human"), loc, 0); + faction *f = addfaction("nobody@eressea.de", NULL, rc ? rc : test_create_race("human"), loc); test_clear_messages(f); return f; } @@ -240,6 +245,29 @@ static void test_reset(void) { free_spellbooks(); free_prefixes(); mt_clear(); +/* + for (i = 0; i != MAXTERRAINS; ++i) { + int flags = 0; + if (i == T_FIREWALL) { + flags |= FORBIDDEN_REGION; + } else { + flags = FLY_INTO | WALK_INTO; + if (i == T_OCEAN) { + flags |= SEA_REGION | SWIM_INTO; + } + else { + flags |= LAND_REGION; + if (i == T_PLAIN) { + flags |= CAVALRY_REGION | FOREST_REGION; + } + else if (i == T_GLACIER || i == T_ICEBERG || i == T_ICEBERG_SLEEP) { + flags |= ARCTIC_REGION; + } + } + } + test_create_terrain(terrainnames[i], flags); + } +*/ for (i = 0; i != MAXSKILLS; ++i) { enable_skill(i, true); } @@ -390,7 +418,9 @@ building_type * test_create_buildingtype(const char * name) con->materials[0].rtype = get_resourcetype(R_STONE); } if (default_locale) { - locale_setstring(default_locale, name, name); + if (locale_getstring(default_locale, name) == NULL) { + locale_setstring(default_locale, name, name); + } } return btype; } diff --git a/src/tests.h b/src/tests.h index d2a77d1b4..17da12d4e 100644 --- a/src/tests.h +++ b/src/tests.h @@ -1,7 +1,6 @@ #ifndef ERESSEA_TESTS_H #define ERESSEA_TESTS_H -#include #include #ifdef __cplusplus @@ -10,6 +9,8 @@ extern "C" { #define ASSERT_DBL_DELTA 0.001 + enum param_t; + struct region; struct unit; struct faction; @@ -61,7 +62,7 @@ extern "C" { struct spell * test_create_spell(void); int test_set_item(struct unit * u, const struct item_type *itype, int value); - void test_translate_param(const struct locale *lang, param_t param, const char *text); + void test_translate_param(const struct locale *lang, enum param_t param, const char *text); const char * test_get_messagetype(const struct message *msg); struct message * test_find_messagetype_ex(struct message_list *msgs, const char *name, struct message *prev); struct message * test_find_messagetype(struct message_list *msgs, const char *name); diff --git a/src/tests.test.c b/src/tests.test.c index 067772262..885d834e8 100644 --- a/src/tests.test.c +++ b/src/tests.test.c @@ -23,13 +23,13 @@ static void test_resources(CuTest *tc) { CuAssertPtrNotNull(tc, rt_find("permaura")); CuAssertPtrEquals(tc, rt_find("permaura"), (void *)get_resourcetype(R_PERMAURA)); - CuAssertPtrEquals(tc, 0, rt_find("stone")); + CuAssertPtrEquals(tc, NULL, rt_find("stone")); rtype = rt_get_or_create("stone"); CuAssertPtrEquals(tc, (void *)rtype, (void *)rt_find("stone")); CuAssertPtrEquals(tc, (void *)rtype, (void *)get_resourcetype(R_STONE)); free_resources(); - CuAssertPtrEquals(tc, 0, rt_find("stone")); - CuAssertPtrEquals(tc, 0, rt_find("peasant")); + CuAssertPtrEquals(tc, NULL, rt_find("stone")); + CuAssertPtrEquals(tc, NULL, rt_find("peasant")); rtype = rt_get_or_create("stone"); CuAssertPtrEquals(tc, (void *)rtype, (void *)get_resourcetype(R_STONE)); test_teardown(); diff --git a/src/travelthru.c b/src/travelthru.c index fa6293f53..5a1af28eb 100644 --- a/src/travelthru.c +++ b/src/travelthru.c @@ -27,7 +27,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include -#include +#include #include #include diff --git a/src/travelthru.test.c b/src/travelthru.test.c index 8a38891b1..b4f0e3dca 100644 --- a/src/travelthru.test.c +++ b/src/travelthru.test.c @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include #include "travelthru.h" diff --git a/src/triggers/changefaction.c b/src/triggers/changefaction.c index f34cb98bd..8b1ead479 100644 --- a/src/triggers/changefaction.c +++ b/src/triggers/changefaction.c @@ -24,10 +24,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include /* util includes */ -#include +#include #include -#include -#include +#include +#include #include #include #include @@ -87,7 +87,7 @@ static int changefaction_read(trigger * t, gamedata *data) changefaction_data *td = (changefaction_data *)t->data.v; read_unit_reference(data, &td->unit, NULL); - return read_faction_reference(data, &td->faction, NULL) > 0 ? AT_READ_OK : AT_READ_FAIL; + return read_faction_reference(data, &td->faction) > 0 ? AT_READ_OK : AT_READ_FAIL; } trigger_type tt_changefaction = { diff --git a/src/triggers/changerace.c b/src/triggers/changerace.c index abc605c35..5a834314a 100644 --- a/src/triggers/changerace.c +++ b/src/triggers/changerace.c @@ -24,10 +24,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include /* util includes */ -#include +#include #include -#include -#include +#include +#include #include #include #include diff --git a/src/triggers/clonedied.c b/src/triggers/clonedied.c index 62c4c3343..c6593c2a4 100644 --- a/src/triggers/clonedied.c +++ b/src/triggers/clonedied.c @@ -26,10 +26,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include /* util includes */ -#include +#include #include -#include -#include +#include +#include #include #include #include diff --git a/src/triggers/createcurse.c b/src/triggers/createcurse.c index bd7422587..544b9aafe 100644 --- a/src/triggers/createcurse.c +++ b/src/triggers/createcurse.c @@ -24,10 +24,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include /* util includes */ -#include +#include #include -#include -#include +#include +#include #include #include #include diff --git a/src/triggers/createunit.c b/src/triggers/createunit.c index f152d3766..82155de55 100644 --- a/src/triggers/createunit.c +++ b/src/triggers/createunit.c @@ -26,10 +26,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include /* util includes */ -#include +#include #include -#include -#include +#include +#include #include #include #include @@ -94,12 +94,12 @@ static int createunit_read(trigger * t, gamedata *data) int id; int result = AT_READ_OK; - id = read_faction_reference(data, &td->f, NULL); + id = read_faction_reference(data, &td->f); if (id <= 0) { result = AT_READ_FAIL; } - read_region_reference(data, &td->r, NULL); + read_region_reference(data, &td->r); td->race = read_race_reference(data->store); if (!td->race) { result = AT_READ_FAIL; diff --git a/src/triggers/gate.c b/src/triggers/gate.c index 4c2c7a9cd..ac3e44b88 100644 --- a/src/triggers/gate.c +++ b/src/triggers/gate.c @@ -18,9 +18,9 @@ #include /* util includes */ -#include -#include -#include +#include +#include +#include #include #include #include @@ -75,8 +75,8 @@ static void gate_write(const trigger * t, struct storage *store) static int gate_read(trigger * t, gamedata *data) { gate_data *gd = (gate_data *)t->data.v; - int bc = read_building_reference(data, &gd->gate, NULL); - int rc = read_region_reference(data, &gd->target, NULL); + int bc = read_building_reference(data, &gd->gate); + int rc = read_region_reference(data, &gd->target); if (bc <= 0 && rc <= 0) { return AT_READ_FAIL; diff --git a/src/triggers/giveitem.c b/src/triggers/giveitem.c index 08e4f0147..118497c86 100644 --- a/src/triggers/giveitem.c +++ b/src/triggers/giveitem.c @@ -24,10 +24,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include /* util includes */ -#include +#include #include -#include -#include +#include +#include #include #include #include diff --git a/src/triggers/killunit.c b/src/triggers/killunit.c index bca630177..0338da4af 100644 --- a/src/triggers/killunit.c +++ b/src/triggers/killunit.c @@ -23,10 +23,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include /* util includes */ -#include +#include #include -#include -#include +#include +#include #include #include #include diff --git a/src/triggers/shock.c b/src/triggers/shock.c index 7eae6f31a..0d0177025 100644 --- a/src/triggers/shock.c +++ b/src/triggers/shock.c @@ -29,10 +29,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include /* util includes */ -#include +#include #include -#include -#include +#include +#include #include #include #include @@ -67,7 +67,7 @@ static void do_shock(unit * u, const char *reason) /* Aura - Verlust */ if (is_mage(u)) { - int aura = max_spellpoints(u->region, u) / 10; + int aura = max_spellpoints_depr(u->region, u) / 10; int now = get_spellpoints(u); if (now > aura) { set_spellpoints(u, aura); diff --git a/src/triggers/shock.test.c b/src/triggers/shock.test.c index 43b8d394b..952febfd0 100644 --- a/src/triggers/shock.test.c +++ b/src/triggers/shock.test.c @@ -5,7 +5,7 @@ #include #include -#include +#include #include #include @@ -23,7 +23,7 @@ static void test_shock(CuTest *tc) { test_setup(); shock_setup(); u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); - create_mage(u, M_GRAY); + create_mage(u, M_GWYRRD); set_level(u, SK_MAGIC, 5); set_spellpoints(u, 10); u->hp = 10; @@ -44,7 +44,7 @@ static void test_shock_low(CuTest *tc) { test_setup(); shock_setup(); u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); - create_mage(u, M_GRAY); + create_mage(u, M_GWYRRD); set_level(u, SK_MAGIC, 5); set_spellpoints(u, 1); u->hp = 1; diff --git a/src/triggers/timeout.c b/src/triggers/timeout.c index 5179bd832..8e8a6b9bf 100644 --- a/src/triggers/timeout.c +++ b/src/triggers/timeout.c @@ -20,9 +20,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "timeout.h" /* util includes */ -#include -#include -#include +#include +#include +#include #include #include diff --git a/src/triggers/triggers.c b/src/triggers/triggers.c index 8826fcba2..13504f216 100644 --- a/src/triggers/triggers.c +++ b/src/triggers/triggers.c @@ -31,7 +31,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include /* util includes */ -#include +#include /* libc includes */ #include diff --git a/src/upkeep.c b/src/upkeep.c index 6748d620c..9ab8c1fea 100644 --- a/src/upkeep.c +++ b/src/upkeep.c @@ -167,7 +167,7 @@ void get_food(region * r) struct faction *owner = region_get_owner(r); /* if the region is owned, and the owner is nice, then we'll get * food from the peasants - should not be used with WORK */ - if (owner != NULL && (get_alliance(owner, u->faction) & HELP_MONEY)) { + if (owner != NULL && alliedfaction(owner, u->faction, HELP_MONEY)) { int rm = rmoney(r); int use = (rm < need) ? rm : need; rsetmoney(r, rm - use); diff --git a/src/upkeep.test.c b/src/upkeep.test.c index f2fedc89b..7f5abd02e 100644 --- a/src/upkeep.test.c +++ b/src/upkeep.test.c @@ -1,6 +1,7 @@ #include #include "upkeep.h" +#include #include #include #include @@ -117,7 +118,7 @@ void test_upkeep_from_friend(CuTest * tc) f1 = test_create_faction(test_create_race("human")); f2 = test_create_faction(test_create_race("human")); assert(f1 && f2); - set_alliance(f1, f2, HELP_MONEY); + ally_set(&f1->allies, f2, HELP_MONEY); u1 = test_create_unit(f1, r); u2 = test_create_unit(f2, r); assert(r && u1 && u2); diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index b462d2bd3..362ee4fb2 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -1,21 +1,23 @@ project(util C) +add_subdirectory (crypto) + SET(_TEST_FILES -attrib.test.c base36.test.c # bsdstring.test.c # crmessage.test.c # dice.test.c -# event.test.c # filereader.test.c functions.test.c -gamedata.test.c # goodies.test.c +keyword.test.c language.test.c # lists.test.c # log.test.c message.test.c # nrmessage.test.c +order_parser.test.c +# param.test.c parser.test.c password.test.c # rand.test.c @@ -31,22 +33,22 @@ variant.test.c ) SET(_FILES -attrib.c base36.c bsdstring.c crmessage.c dice.c -event.c filereader.c functions.c -gamedata.c goodies.c +keyword.c language.c lists.c log.c message.c mt19937ar.c nrmessage.c +order_parser.c +param.c parser.c password.c path.c diff --git a/src/util/base36.h b/src/util/base36.h index 05c81d2c0..33f0d2f08 100644 --- a/src/util/base36.h +++ b/src/util/base36.h @@ -31,6 +31,7 @@ extern "C" { const char *itoa36(int i); const char *itoa10(int i); extern int atoi36(const char *s); + extern int atoi10(const char *s); int i10toi36(int i); #ifdef __cplusplus diff --git a/src/util/crypto/CMakeLists.txt b/src/util/crypto/CMakeLists.txt new file mode 100644 index 000000000..195eb02b4 --- /dev/null +++ b/src/util/crypto/CMakeLists.txt @@ -0,0 +1,27 @@ +cmake_minimum_required(VERSION 2.6) +project (crypto C) + +IF (MSVC) + include (MSVC) + MSVC_SET_WARNING_LEVEL(3) +ENDIF (MSVC) + +SET (LIB_SRC + crypto.c + crypt_blowfish/wrapper.c + crypt_blowfish/crypt_blowfish.c + crypt_blowfish/crypt_gensalt.c +) +ADD_LIBRARY (crypto ${LIB_SRC}) + +set (CRYPTO_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "cJSON headers") +set (CRYPTO_LIBRARIES crypto CACHE INTERNAL "crypto libraries") + +IF(WIN32) + SET(CRYPTO_LIBRARIES ${CRYPTO_LIBRARIES} bcrypt CACHE + INTERNAL "crypto libraries") +ENDIF() + +IF (MSVC) + MSVC_CRT_SECURE_NO_WARNINGS (crypto) +ENDIF (MSVC) diff --git a/src/util/crypto/crypt_blowfish/LINKS b/src/util/crypto/crypt_blowfish/LINKS new file mode 100644 index 000000000..a6cb7e1c3 --- /dev/null +++ b/src/util/crypto/crypt_blowfish/LINKS @@ -0,0 +1,29 @@ +New versions of this package (crypt_blowfish): + + http://www.openwall.com/crypt/ + +A paper on the algorithm that explains its design decisions: + + http://www.usenix.org/events/usenix99/provos.html + +Unix Seventh Edition Manual, Volume 2: the password scheme (1978): + + http://plan9.bell-labs.com/7thEdMan/vol2/password + +The Openwall GNU/*/Linux (Owl) tcb suite implementing the alternative +password shadowing scheme. This includes a PAM module which +supersedes pam_unix and uses the password hashing framework provided +with crypt_blowfish when setting new passwords. + + http://www.openwall.com/tcb/ + +pam_passwdqc, a password strength checking and policy enforcement +module for PAM-aware password changing programs: + + http://www.openwall.com/passwdqc/ + +John the Ripper password cracker: + + http://www.openwall.com/john/ + +$Owl: Owl/packages/glibc/crypt_blowfish/LINKS,v 1.4 2005/11/16 13:09:47 solar Exp $ diff --git a/src/util/crypto/crypt_blowfish/PERFORMANCE b/src/util/crypto/crypt_blowfish/PERFORMANCE new file mode 100644 index 000000000..9d6fe4ef5 --- /dev/null +++ b/src/util/crypto/crypt_blowfish/PERFORMANCE @@ -0,0 +1,30 @@ +These numbers are for 32 iterations ("$2a$05"): + + OpenBSD 3.0 bcrypt(*) crypt_blowfish 0.4.4 +Pentium III, 840 MHz 99 c/s 121 c/s (+22%) +Alpha 21164PC, 533 MHz 55.5 c/s 76.9 c/s (+38%) +UltraSparc IIi, 400 MHz 49.9 c/s 52.5 c/s (+5%) +Pentium, 120 MHz 8.8 c/s 20.1 c/s (+128%) +PA-RISC 7100LC, 80 MHz 8.5 c/s 16.3 c/s (+92%) + +(*) built with -fomit-frame-pointer -funroll-loops, which I don't +think happens for libcrypt. + +Starting with version 1.1 released in June 2011, default builds of +crypt_blowfish invoke a quick self-test on every hash computation. +This has roughly a 4.8% performance impact at "$2a$05", but only a 0.6% +impact at a more typical setting of "$2a$08". + +The large speedup for the original Pentium is due to the assembly +code and the weird optimizations this processor requires. + +The numbers for password cracking are 2 to 10% higher than those for +crypt_blowfish as certain things may be done out of the loop and the +code doesn't need to be reentrant. + +Recent versions of John the Ripper (1.6.25-dev and newer) achieve an +additional 15% speedup on the Pentium Pro family of processors (which +includes Pentium III) with a separate version of the assembly code and +run-time CPU detection. + +$Owl: Owl/packages/glibc/crypt_blowfish/PERFORMANCE,v 1.6 2011/06/21 12:09:20 solar Exp $ diff --git a/src/util/crypto/crypt_blowfish/README b/src/util/crypto/crypt_blowfish/README new file mode 100644 index 000000000..e95da230e --- /dev/null +++ b/src/util/crypto/crypt_blowfish/README @@ -0,0 +1,68 @@ +This is an implementation of a password hashing method, provided via the +crypt(3) and a reentrant interface. It is fully compatible with +OpenBSD's bcrypt.c for prefix "$2b$", originally by Niels Provos and +David Mazieres. (Please refer to the included crypt(3) man page for +information on minor compatibility issues for other bcrypt prefixes.) + +I've placed this code in the public domain, with fallback to a +permissive license. Please see the comment in crypt_blowfish.c for +more information. + +You can use the provided routines in your own packages, or link them +into a C library. I've provided hooks for linking into GNU libc, but +it shouldn't be too hard to get this into another C library. Note +that simply adding this code into your libc is probably not enough to +make your system use the new password hashing algorithm. Changes to +passwd(1), PAM modules, or whatever else your system uses will likely +be needed as well. These are not a part of this package, but see +LINKS for a pointer to our tcb suite. + +Instructions on using the routines in one of the two common ways are +given below. It is recommended that you test the routines on your +system before you start. Type "make check" or "make check_threads" +(if you have the POSIX threads library), then "make clean". + + +1. Using the routines in your programs. + +The available interfaces are in ow-crypt.h, and this is the file you +should include. You won't need crypt.h. When linking, add all of the +C files and x86.S (you can compile and link it even on a non-x86, it +will produce no code in this case). + + +2. Building the routines into GNU C library. + +For versions 2.13 and 2.14 (and likely other nearby ones), extract the +library sources as usual. Apply the patch for glibc 2.14 provided in +this package. Enter crypt/ and rename crypt.h to gnu-crypt.h within +that directory. Copy the C sources, header, and assembly (x86.S) files +from this package in there as well (but be sure you don't overwrite the +Makefile). Configure, build, and install the library as usual. + +For versions 2.2 to 2.3.6 (and likely also for some newer ones), +extract the library sources and maybe its optional add-ons as usual. +Apply the patch for glibc 2.3.6 provided in this package. Enter +crypt/ and rename crypt.h to gnu-crypt.h within that directory. Copy +the C sources, header, and assembly (x86.S) files from this package in +there as well (but be sure you don't overwrite the Makefile). +Configure, build, and install the library as usual. + +For versions 2.1 to 2.1.3, extract the library sources and the crypt +and linuxthreads add-ons as usual. Apply the patch for glibc 2.1.3 +provided in this package. Enter crypt/sysdeps/unix/, and rename +crypt.h to gnu-crypt.h within that directory. Copy C sources, header, +and assembly (x86.S) files from this package in there as well (but be +sure you don't overwrite the Makefile). Configure, build, and install +the library as usual. + +Programs that want to use the provided interfaces will need to include +crypt.h (but not ow-crypt.h directly). By default, prototypes for the +new routines aren't defined (but the extra functionality of crypt(3) +is indeed available). You need to define _OW_SOURCE to obtain the new +routines as well. + +-- +Solar Designer + +$Owl: Owl/packages/glibc/crypt_blowfish/README,v 1.10 2014/07/07 15:19:04 solar Exp $ diff --git a/src/util/crypto/crypt_blowfish/crypt.h b/src/util/crypto/crypt_blowfish/crypt.h new file mode 100644 index 000000000..12e67055b --- /dev/null +++ b/src/util/crypto/crypt_blowfish/crypt.h @@ -0,0 +1,24 @@ +/* + * Written by Solar Designer in 2000-2002. + * No copyright is claimed, and the software is hereby placed in the public + * domain. In case this attempt to disclaim copyright and place the software + * in the public domain is deemed null and void, then the software is + * Copyright (c) 2000-2002 Solar Designer and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * See crypt_blowfish.c for more information. + */ + +#include + +#if defined(_OW_SOURCE) || defined(__USE_OW) +#define __SKIP_GNU +#undef __SKIP_OW +#include +#undef __SKIP_GNU +#endif diff --git a/src/util/crypto/crypt_blowfish/crypt_blowfish.c b/src/util/crypto/crypt_blowfish/crypt_blowfish.c new file mode 100644 index 000000000..701ddddf0 --- /dev/null +++ b/src/util/crypto/crypt_blowfish/crypt_blowfish.c @@ -0,0 +1,904 @@ +/* + * The crypt_blowfish homepage is: + * + * http://www.openwall.com/crypt/ + * + * This code comes from John the Ripper password cracker, with reentrant + * and crypt(3) interfaces added, but optimizations specific to password + * cracking removed. + * + * Written by Solar Designer in 1998-2014. + * No copyright is claimed, and the software is hereby placed in the public + * domain. In case this attempt to disclaim copyright and place the software + * in the public domain is deemed null and void, then the software is + * Copyright (c) 1998-2014 Solar Designer and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * It is my intent that you should be able to use this on your system, + * as part of a software package, or anywhere else to improve security, + * ensure compatibility, or for any other purpose. I would appreciate + * it if you give credit where it is due and keep your modifications in + * the public domain as well, but I don't require that in order to let + * you place this code and any modifications you make under a license + * of your choice. + * + * This implementation is fully compatible with OpenBSD's bcrypt.c for prefix + * "$2b$", originally by Niels Provos , and it uses + * some of his ideas. The password hashing algorithm was designed by David + * Mazieres . For information on the level of + * compatibility for bcrypt hash prefixes other than "$2b$", please refer to + * the comments in BF_set_key() below and to the included crypt(3) man page. + * + * There's a paper on the algorithm that explains its design decisions: + * + * http://www.usenix.org/events/usenix99/provos.html + * + * Some of the tricks in BF_ROUND might be inspired by Eric Young's + * Blowfish library (I can't be sure if I would think of something if I + * hadn't seen his code). + */ + +#include + +#include +#ifndef __set_errno +#define __set_errno(val) errno = (val) +#endif + +/* Just to make sure the prototypes match the actual definitions */ +#include "crypt_blowfish.h" + +#if defined(__x86_64__) || defined(__alpha__) || defined(__hppa__) +#define BF_ASM 0 +#define BF_SCALE 1 +#else +#define BF_ASM 0 +#define BF_SCALE 0 +#endif + +typedef unsigned int BF_word; +typedef signed int BF_word_signed; + +/* Number of Blowfish rounds, this is also hardcoded into a few places */ +#define BF_N 16 + +typedef BF_word BF_key[BF_N + 2]; + +typedef struct { + BF_word S[4][0x100]; + BF_key P; +} BF_ctx; + +/* + * Magic IV for 64 Blowfish encryptions that we do at the end. + * The string is "OrpheanBeholderScryDoubt" on big-endian. + */ +static BF_word BF_magic_w[6] = { + 0x4F727068, 0x65616E42, 0x65686F6C, + 0x64657253, 0x63727944, 0x6F756274 +}; + +/* + * P-box and S-box tables initialized with digits of Pi. + */ +static BF_ctx BF_init_state = { + { + { + 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, + 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, + 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, + 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, + 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, + 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, + 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, + 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, + 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, + 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, + 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, + 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, + 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, + 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, + 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, + 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, + 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, + 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, + 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, + 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0, + 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, + 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, + 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, + 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, + 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, + 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, + 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, + 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, + 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, + 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, + 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, + 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, + 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, + 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, + 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, + 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, + 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, + 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, + 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, + 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, + 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, + 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, + 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, + 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, + 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, + 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, + 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, + 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, + 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, + 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, + 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, + 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, + 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, + 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, + 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, + 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af, + 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, + 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, + 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, + 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, + 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, + 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915, + 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, + 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a + }, { + 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, + 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266, + 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, + 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, + 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, + 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, + 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, + 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1, + 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, + 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, + 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, + 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, + 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, + 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7, + 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, + 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, + 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, + 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, + 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, + 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87, + 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, + 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, + 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, + 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, + 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, + 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509, + 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, + 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, + 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, + 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, + 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, + 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, + 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, + 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, + 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, + 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, + 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, + 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf, + 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, + 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, + 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, + 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, + 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, + 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, + 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, + 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, + 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, + 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, + 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, + 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, + 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, + 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, + 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, + 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, + 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, + 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061, + 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, + 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, + 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, + 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, + 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, + 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340, + 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, + 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7 + }, { + 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, + 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, + 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, + 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, + 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, + 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, + 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, + 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, + 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, + 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, + 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, + 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, + 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, + 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, + 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, + 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, + 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, + 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, + 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, + 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, + 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, + 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, + 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, + 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, + 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, + 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, + 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, + 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, + 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, + 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, + 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, + 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, + 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, + 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, + 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, + 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, + 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, + 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, + 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, + 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, + 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, + 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, + 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, + 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, + 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, + 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, + 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, + 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, + 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, + 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, + 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, + 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, + 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, + 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, + 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, + 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62, + 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, + 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, + 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, + 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, + 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, + 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, + 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, + 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0 + }, { + 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, + 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe, + 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, + 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, + 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, + 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, + 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, + 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22, + 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, + 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, + 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, + 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, + 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, + 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51, + 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, + 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, + 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, + 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, + 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, + 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd, + 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, + 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, + 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, + 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, + 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, + 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, + 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, + 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, + 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, + 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, + 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, + 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47, + 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, + 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, + 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, + 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, + 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, + 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, + 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, + 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, + 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, + 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, + 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, + 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525, + 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, + 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, + 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, + 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, + 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, + 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d, + 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, + 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, + 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, + 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, + 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, + 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, + 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, + 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, + 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, + 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, + 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, + 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9, + 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, + 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6 + } + }, { + 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, + 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, + 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, + 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, + 0x9216d5d9, 0x8979fb1b + } +}; + +static unsigned char BF_itoa64[64 + 1] = + "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + +static unsigned char BF_atoi64[0x60] = { + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 1, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 64, 64, 64, 64, 64, + 64, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 64, 64, 64, 64, 64, + 64, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 64, 64, 64, 64, 64 +}; + +#define BF_safe_atoi64(dst, src) \ +{ \ + tmp = (unsigned char)(src); \ + if ((unsigned int)(tmp -= 0x20) >= 0x60) return -1; \ + tmp = BF_atoi64[tmp]; \ + if (tmp > 63) return -1; \ + (dst) = tmp; \ +} + +static int BF_decode(BF_word *dst, const char *src, int size) +{ + unsigned char *dptr = (unsigned char *)dst; + unsigned char *end = dptr + size; + const unsigned char *sptr = (const unsigned char *)src; + unsigned int tmp, c1, c2, c3, c4; + + do { + BF_safe_atoi64(c1, *sptr++); + BF_safe_atoi64(c2, *sptr++); + *dptr++ = (c1 << 2) | ((c2 & 0x30) >> 4); + if (dptr >= end) break; + + BF_safe_atoi64(c3, *sptr++); + *dptr++ = ((c2 & 0x0F) << 4) | ((c3 & 0x3C) >> 2); + if (dptr >= end) break; + + BF_safe_atoi64(c4, *sptr++); + *dptr++ = ((c3 & 0x03) << 6) | c4; + } while (dptr < end); + + return 0; +} + +static void BF_encode(char *dst, const BF_word *src, int size) +{ + const unsigned char *sptr = (const unsigned char *)src; + const unsigned char *end = sptr + size; + unsigned char *dptr = (unsigned char *)dst; + unsigned int c1, c2; + + do { + c1 = *sptr++; + *dptr++ = BF_itoa64[c1 >> 2]; + c1 = (c1 & 0x03) << 4; + if (sptr >= end) { + *dptr++ = BF_itoa64[c1]; + break; + } + + c2 = *sptr++; + c1 |= c2 >> 4; + *dptr++ = BF_itoa64[c1]; + c1 = (c2 & 0x0f) << 2; + if (sptr >= end) { + *dptr++ = BF_itoa64[c1]; + break; + } + + c2 = *sptr++; + c1 |= c2 >> 6; + *dptr++ = BF_itoa64[c1]; + *dptr++ = BF_itoa64[c2 & 0x3f]; + } while (sptr < end); +} + +static void BF_swap(BF_word *x, int count) +{ + static int endianness_check = 1; + char *is_little_endian = (char *)&endianness_check; + BF_word tmp; + + if (*is_little_endian) + do { + tmp = *x; + tmp = (tmp << 16) | (tmp >> 16); + *x++ = ((tmp & 0x00FF00FF) << 8) | ((tmp >> 8) & 0x00FF00FF); + } while (--count); +} + +#if BF_SCALE +/* Architectures which can shift addresses left by 2 bits with no extra cost */ +#define BF_ROUND(L, R, N) \ + tmp1 = L & 0xFF; \ + tmp2 = L >> 8; \ + tmp2 &= 0xFF; \ + tmp3 = L >> 16; \ + tmp3 &= 0xFF; \ + tmp4 = L >> 24; \ + tmp1 = data.ctx.S[3][tmp1]; \ + tmp2 = data.ctx.S[2][tmp2]; \ + tmp3 = data.ctx.S[1][tmp3]; \ + tmp3 += data.ctx.S[0][tmp4]; \ + tmp3 ^= tmp2; \ + R ^= data.ctx.P[N + 1]; \ + tmp3 += tmp1; \ + R ^= tmp3; +#else +/* Architectures with no complicated addressing modes supported */ +#define BF_INDEX(S, i) \ + (*((BF_word *)(((unsigned char *)S) + (i)))) +#define BF_ROUND(L, R, N) \ + tmp1 = L & 0xFF; \ + tmp1 <<= 2; \ + tmp2 = L >> 6; \ + tmp2 &= 0x3FC; \ + tmp3 = L >> 14; \ + tmp3 &= 0x3FC; \ + tmp4 = L >> 22; \ + tmp4 &= 0x3FC; \ + tmp1 = BF_INDEX(data.ctx.S[3], tmp1); \ + tmp2 = BF_INDEX(data.ctx.S[2], tmp2); \ + tmp3 = BF_INDEX(data.ctx.S[1], tmp3); \ + tmp3 += BF_INDEX(data.ctx.S[0], tmp4); \ + tmp3 ^= tmp2; \ + R ^= data.ctx.P[N + 1]; \ + tmp3 += tmp1; \ + R ^= tmp3; +#endif + +/* + * Encrypt one block, BF_N is hardcoded here. + */ +#define BF_ENCRYPT \ + L ^= data.ctx.P[0]; \ + BF_ROUND(L, R, 0); \ + BF_ROUND(R, L, 1); \ + BF_ROUND(L, R, 2); \ + BF_ROUND(R, L, 3); \ + BF_ROUND(L, R, 4); \ + BF_ROUND(R, L, 5); \ + BF_ROUND(L, R, 6); \ + BF_ROUND(R, L, 7); \ + BF_ROUND(L, R, 8); \ + BF_ROUND(R, L, 9); \ + BF_ROUND(L, R, 10); \ + BF_ROUND(R, L, 11); \ + BF_ROUND(L, R, 12); \ + BF_ROUND(R, L, 13); \ + BF_ROUND(L, R, 14); \ + BF_ROUND(R, L, 15); \ + tmp4 = R; \ + R = L; \ + L = tmp4 ^ data.ctx.P[BF_N + 1]; + +#if BF_ASM +#define BF_body() \ + _BF_body_r(&data.ctx); +#else +#define BF_body() \ + L = R = 0; \ + ptr = data.ctx.P; \ + do { \ + ptr += 2; \ + BF_ENCRYPT; \ + *(ptr - 2) = L; \ + *(ptr - 1) = R; \ + } while (ptr < &data.ctx.P[BF_N + 2]); \ +\ + ptr = data.ctx.S[0]; \ + do { \ + ptr += 2; \ + BF_ENCRYPT; \ + *(ptr - 2) = L; \ + *(ptr - 1) = R; \ + } while (ptr < &data.ctx.S[3][0xFF]); +#endif + +static void BF_set_key(const char *key, BF_key expanded, BF_key initial, + unsigned char flags) +{ + const char *ptr = key; + unsigned int bug, i, j; + BF_word safety, sign, diff, tmp[2]; + +/* + * There was a sign extension bug in older revisions of this function. While + * we would have liked to simply fix the bug and move on, we have to provide + * a backwards compatibility feature (essentially the bug) for some systems and + * a safety measure for some others. The latter is needed because for certain + * multiple inputs to the buggy algorithm there exist easily found inputs to + * the correct algorithm that produce the same hash. Thus, we optionally + * deviate from the correct algorithm just enough to avoid such collisions. + * While the bug itself affected the majority of passwords containing + * characters with the 8th bit set (although only a percentage of those in a + * collision-producing way), the anti-collision safety measure affects + * only a subset of passwords containing the '\xff' character (not even all of + * those passwords, just some of them). This character is not found in valid + * UTF-8 sequences and is rarely used in popular 8-bit character encodings. + * Thus, the safety measure is unlikely to cause much annoyance, and is a + * reasonable tradeoff to use when authenticating against existing hashes that + * are not reliably known to have been computed with the correct algorithm. + * + * We use an approach that tries to minimize side-channel leaks of password + * information - that is, we mostly use fixed-cost bitwise operations instead + * of branches or table lookups. (One conditional branch based on password + * length remains. It is not part of the bug aftermath, though, and is + * difficult and possibly unreasonable to avoid given the use of C strings by + * the caller, which results in similar timing leaks anyway.) + * + * For actual implementation, we set an array index in the variable "bug" + * (0 means no bug, 1 means sign extension bug emulation) and a flag in the + * variable "safety" (bit 16 is set when the safety measure is requested). + * Valid combinations of settings are: + * + * Prefix "$2a$": bug = 0, safety = 0x10000 + * Prefix "$2b$": bug = 0, safety = 0 + * Prefix "$2x$": bug = 1, safety = 0 + * Prefix "$2y$": bug = 0, safety = 0 + */ + bug = (unsigned int)flags & 1; + safety = ((BF_word)flags & 2) << 15; + + sign = diff = 0; + + for (i = 0; i < BF_N + 2; i++) { + tmp[0] = tmp[1] = 0; + for (j = 0; j < 4; j++) { + tmp[0] <<= 8; + tmp[0] |= (unsigned char)*ptr; /* correct */ + tmp[1] <<= 8; + tmp[1] |= (BF_word_signed)(signed char)*ptr; /* bug */ +/* + * Sign extension in the first char has no effect - nothing to overwrite yet, + * and those extra 24 bits will be fully shifted out of the 32-bit word. For + * chars 2, 3, 4 in each four-char block, we set bit 7 of "sign" if sign + * extension in tmp[1] occurs. Once this flag is set, it remains set. + */ + if (j) + sign |= tmp[1] & 0x80; + if (!*ptr) + ptr = key; + else + ptr++; + } + diff |= tmp[0] ^ tmp[1]; /* Non-zero on any differences */ + + expanded[i] = tmp[bug]; + initial[i] = BF_init_state.P[i] ^ tmp[bug]; + } + +/* + * At this point, "diff" is zero iff the correct and buggy algorithms produced + * exactly the same result. If so and if "sign" is non-zero, which indicates + * that there was a non-benign sign extension, this means that we have a + * collision between the correctly computed hash for this password and a set of + * passwords that could be supplied to the buggy algorithm. Our safety measure + * is meant to protect from such many-buggy to one-correct collisions, by + * deviating from the correct algorithm in such cases. Let's check for this. + */ + diff |= diff >> 16; /* still zero iff exact match */ + diff &= 0xffff; /* ditto */ + diff += 0xffff; /* bit 16 set iff "diff" was non-zero (on non-match) */ + sign <<= 9; /* move the non-benign sign extension flag to bit 16 */ + sign &= ~diff & safety; /* action needed? */ + +/* + * If we have determined that we need to deviate from the correct algorithm, + * flip bit 16 in initial expanded key. (The choice of 16 is arbitrary, but + * let's stick to it now. It came out of the approach we used above, and it's + * not any worse than any other choice we could make.) + * + * It is crucial that we don't do the same to the expanded key used in the main + * Eksblowfish loop. By doing it to only one of these two, we deviate from a + * state that could be directly specified by a password to the buggy algorithm + * (and to the fully correct one as well, but that's a side-effect). + */ + initial[0] ^= sign; +} + +static const unsigned char flags_by_subtype[26] = + {2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 0}; + +static char *BF_crypt(const char *key, const char *setting, + char *output, int size, + BF_word min) +{ +#if BF_ASM + extern void _BF_body_r(BF_ctx *ctx); +#endif + struct { + BF_ctx ctx; + BF_key expanded_key; + union { + BF_word salt[4]; + BF_word output[6]; + } binary; + } data; + BF_word L, R; + BF_word tmp1, tmp2, tmp3, tmp4; + BF_word *ptr; + BF_word count; + int i; + + if (size < 7 + 22 + 31 + 1) { + __set_errno(ERANGE); + return NULL; + } + + if (setting[0] != '$' || + setting[1] != '2' || + setting[2] < 'a' || setting[2] > 'z' || + !flags_by_subtype[(unsigned int)(unsigned char)setting[2] - 'a'] || + setting[3] != '$' || + setting[4] < '0' || setting[4] > '3' || + setting[5] < '0' || setting[5] > '9' || + (setting[4] == '3' && setting[5] > '1') || + setting[6] != '$') { + __set_errno(EINVAL); + return NULL; + } + + count = (BF_word)1 << ((setting[4] - '0') * 10 + (setting[5] - '0')); + if (count < min || BF_decode(data.binary.salt, &setting[7], 16)) { + __set_errno(EINVAL); + return NULL; + } + BF_swap(data.binary.salt, 4); + + BF_set_key(key, data.expanded_key, data.ctx.P, + flags_by_subtype[(unsigned int)(unsigned char)setting[2] - 'a']); + + memcpy(data.ctx.S, BF_init_state.S, sizeof(data.ctx.S)); + + L = R = 0; + for (i = 0; i < BF_N + 2; i += 2) { + L ^= data.binary.salt[i & 2]; + R ^= data.binary.salt[(i & 2) + 1]; + BF_ENCRYPT; + data.ctx.P[i] = L; + data.ctx.P[i + 1] = R; + } + + ptr = data.ctx.S[0]; + do { + ptr += 4; + L ^= data.binary.salt[(BF_N + 2) & 3]; + R ^= data.binary.salt[(BF_N + 3) & 3]; + BF_ENCRYPT; + *(ptr - 4) = L; + *(ptr - 3) = R; + + L ^= data.binary.salt[(BF_N + 4) & 3]; + R ^= data.binary.salt[(BF_N + 5) & 3]; + BF_ENCRYPT; + *(ptr - 2) = L; + *(ptr - 1) = R; + } while (ptr < &data.ctx.S[3][0xFF]); + + do { + int done; + + for (i = 0; i < BF_N + 2; i += 2) { + data.ctx.P[i] ^= data.expanded_key[i]; + data.ctx.P[i + 1] ^= data.expanded_key[i + 1]; + } + + done = 0; + do { + BF_body(); + if (done) + break; + done = 1; + + tmp1 = data.binary.salt[0]; + tmp2 = data.binary.salt[1]; + tmp3 = data.binary.salt[2]; + tmp4 = data.binary.salt[3]; + for (i = 0; i < BF_N; i += 4) { + data.ctx.P[i] ^= tmp1; + data.ctx.P[i + 1] ^= tmp2; + data.ctx.P[i + 2] ^= tmp3; + data.ctx.P[i + 3] ^= tmp4; + } + data.ctx.P[16] ^= tmp1; + data.ctx.P[17] ^= tmp2; + } while (1); + } while (--count); + + for (i = 0; i < 6; i += 2) { + L = BF_magic_w[i]; + R = BF_magic_w[i + 1]; + + count = 64; + do { + BF_ENCRYPT; + } while (--count); + + data.binary.output[i] = L; + data.binary.output[i + 1] = R; + } + + memcpy(output, setting, 7 + 22 - 1); + output[7 + 22 - 1] = BF_itoa64[(int) + BF_atoi64[(int)setting[7 + 22 - 1] - 0x20] & 0x30]; + +/* This has to be bug-compatible with the original implementation, so + * only encode 23 of the 24 bytes. :-) */ + BF_swap(data.binary.output, 6); + BF_encode(&output[7 + 22], data.binary.output, 23); + output[7 + 22 + 31] = '\0'; + + return output; +} + +int _crypt_output_magic(const char *setting, char *output, int size) +{ + if (size < 3) + return -1; + + output[0] = '*'; + output[1] = '0'; + output[2] = '\0'; + + if (setting[0] == '*' && setting[1] == '0') + output[1] = '1'; + + return 0; +} + +/* + * Please preserve the runtime self-test. It serves two purposes at once: + * + * 1. We really can't afford the risk of producing incompatible hashes e.g. + * when there's something like gcc bug 26587 again, whereas an application or + * library integrating this code might not also integrate our external tests or + * it might not run them after every build. Even if it does, the miscompile + * might only occur on the production build, but not on a testing build (such + * as because of different optimization settings). It is painful to recover + * from incorrectly-computed hashes - merely fixing whatever broke is not + * enough. Thus, a proactive measure like this self-test is needed. + * + * 2. We don't want to leave sensitive data from our actual password hash + * computation on the stack or in registers. Previous revisions of the code + * would do explicit cleanups, but simply running the self-test after hash + * computation is more reliable. + * + * The performance cost of this quick self-test is around 0.6% at the "$2a$08" + * setting. + */ +char *_crypt_blowfish_rn(const char *key, const char *setting, + char *output, int size) +{ + const char *test_key = "8b \xd0\xc1\xd2\xcf\xcc\xd8"; + const char *test_setting = "$2a$00$abcdefghijklmnopqrstuu"; + static const char * const test_hashes[2] = + {"i1D709vfamulimlGcq0qq3UvuUasvEa\0\x55", /* 'a', 'b', 'y' */ + "VUrPmXD6q/nVSSp7pNDhCR9071IfIRe\0\x55"}; /* 'x' */ + const char *test_hash = test_hashes[0]; + char *retval; + const char *p; + int save_errno, ok; + struct { + char s[7 + 22 + 1]; + char o[7 + 22 + 31 + 1 + 1 + 1]; + } buf; + +/* Hash the supplied password */ + _crypt_output_magic(setting, output, size); + retval = BF_crypt(key, setting, output, size, 16); + save_errno = errno; + +/* + * Do a quick self-test. It is important that we make both calls to BF_crypt() + * from the same scope such that they likely use the same stack locations, + * which makes the second call overwrite the first call's sensitive data on the + * stack and makes it more likely that any alignment related issues would be + * detected by the self-test. + */ + memcpy(buf.s, test_setting, sizeof(buf.s)); + if (retval) { + unsigned int flags = flags_by_subtype[ + (unsigned int)(unsigned char)setting[2] - 'a']; + test_hash = test_hashes[flags & 1]; + buf.s[2] = setting[2]; + } + memset(buf.o, 0x55, sizeof(buf.o)); + buf.o[sizeof(buf.o) - 1] = 0; + p = BF_crypt(test_key, buf.s, buf.o, sizeof(buf.o) - (1 + 1), 1); + + ok = (p == buf.o && + !memcmp(p, buf.s, 7 + 22) && + !memcmp(p + (7 + 22), test_hash, 31 + 1 + 1 + 1)); + + { + const char *k = "\xff\xa3" "34" "\xff\xff\xff\xa3" "345"; + BF_key ae, ai, ye, yi; + BF_set_key(k, ae, ai, 2); /* $2a$ */ + BF_set_key(k, ye, yi, 4); /* $2y$ */ + ai[0] ^= 0x10000; /* undo the safety (for comparison) */ + ok = ok && ai[0] == 0xdb9c59bc && ye[17] == 0x33343500 && + !memcmp(ae, ye, sizeof(ae)) && + !memcmp(ai, yi, sizeof(ai)); + } + + __set_errno(save_errno); + if (ok) + return retval; + +/* Should not happen */ + _crypt_output_magic(setting, output, size); + __set_errno(EINVAL); /* pretend we don't support this hash type */ + return NULL; +} + +char *_crypt_gensalt_blowfish_rn(const char *prefix, unsigned long count, + const char *input, int size, char *output, int output_size) +{ + if (size < 16 || output_size < 7 + 22 + 1 || + (count && (count < 4 || count > 31)) || + prefix[0] != '$' || prefix[1] != '2' || + (prefix[2] != 'a' && prefix[2] != 'b' && prefix[2] != 'y')) { + if (output_size > 0) output[0] = '\0'; + __set_errno((output_size < 7 + 22 + 1) ? ERANGE : EINVAL); + return NULL; + } + + if (!count) count = 5; + + output[0] = '$'; + output[1] = '2'; + output[2] = prefix[2]; + output[3] = '$'; + output[4] = '0' + (char)count / 10; + output[5] = '0' + count % 10; + output[6] = '$'; + + BF_encode(&output[7], (const BF_word *)input, 16); + output[7 + 22] = '\0'; + + return output; +} diff --git a/src/util/crypto/crypt_blowfish/crypt_blowfish.h b/src/util/crypto/crypt_blowfish/crypt_blowfish.h new file mode 100644 index 000000000..2ee0d8c1d --- /dev/null +++ b/src/util/crypto/crypt_blowfish/crypt_blowfish.h @@ -0,0 +1,27 @@ +/* + * Written by Solar Designer in 2000-2011. + * No copyright is claimed, and the software is hereby placed in the public + * domain. In case this attempt to disclaim copyright and place the software + * in the public domain is deemed null and void, then the software is + * Copyright (c) 2000-2011 Solar Designer and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * See crypt_blowfish.c for more information. + */ + +#ifndef _CRYPT_BLOWFISH_H +#define _CRYPT_BLOWFISH_H + +extern int _crypt_output_magic(const char *setting, char *output, int size); +extern char *_crypt_blowfish_rn(const char *key, const char *setting, + char *output, int size); +extern char *_crypt_gensalt_blowfish_rn(const char *prefix, + unsigned long count, + const char *input, int size, char *output, int output_size); + +#endif diff --git a/src/util/crypto/crypt_blowfish/crypt_gensalt.c b/src/util/crypto/crypt_blowfish/crypt_gensalt.c new file mode 100644 index 000000000..73c15a1ad --- /dev/null +++ b/src/util/crypto/crypt_blowfish/crypt_gensalt.c @@ -0,0 +1,124 @@ +/* + * Written by Solar Designer in 2000-2011. + * No copyright is claimed, and the software is hereby placed in the public + * domain. In case this attempt to disclaim copyright and place the software + * in the public domain is deemed null and void, then the software is + * Copyright (c) 2000-2011 Solar Designer and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * See crypt_blowfish.c for more information. + * + * This file contains salt generation functions for the traditional and + * other common crypt(3) algorithms, except for bcrypt which is defined + * entirely in crypt_blowfish.c. + */ + +#include + +#include +#ifndef __set_errno +#define __set_errno(val) errno = (val) +#endif + +/* Just to make sure the prototypes match the actual definitions */ +#include "crypt_gensalt.h" + +unsigned char _crypt_itoa64[64 + 1] = + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +char *_crypt_gensalt_traditional_rn(const char *prefix, unsigned long count, + const char *input, int size, char *output, int output_size) +{ + (void) prefix; + + if (size < 2 || output_size < 2 + 1 || (count && count != 25)) { + if (output_size > 0) output[0] = '\0'; + __set_errno((output_size < 2 + 1) ? ERANGE : EINVAL); + return NULL; + } + + output[0] = _crypt_itoa64[(unsigned int)input[0] & 0x3f]; + output[1] = _crypt_itoa64[(unsigned int)input[1] & 0x3f]; + output[2] = '\0'; + + return output; +} + +char *_crypt_gensalt_extended_rn(const char *prefix, unsigned long count, + const char *input, int size, char *output, int output_size) +{ + unsigned long value; + + (void) prefix; + +/* Even iteration counts make it easier to detect weak DES keys from a look + * at the hash, so they should be avoided */ + if (size < 3 || output_size < 1 + 4 + 4 + 1 || + (count && (count > 0xffffff || !(count & 1)))) { + if (output_size > 0) output[0] = '\0'; + __set_errno((output_size < 1 + 4 + 4 + 1) ? ERANGE : EINVAL); + return NULL; + } + + if (!count) count = 725; + + output[0] = '_'; + output[1] = _crypt_itoa64[count & 0x3f]; + output[2] = _crypt_itoa64[(count >> 6) & 0x3f]; + output[3] = _crypt_itoa64[(count >> 12) & 0x3f]; + output[4] = _crypt_itoa64[(count >> 18) & 0x3f]; + value = (unsigned long)(unsigned char)input[0] | + ((unsigned long)(unsigned char)input[1] << 8) | + ((unsigned long)(unsigned char)input[2] << 16); + output[5] = _crypt_itoa64[value & 0x3f]; + output[6] = _crypt_itoa64[(value >> 6) & 0x3f]; + output[7] = _crypt_itoa64[(value >> 12) & 0x3f]; + output[8] = _crypt_itoa64[(value >> 18) & 0x3f]; + output[9] = '\0'; + + return output; +} + +char *_crypt_gensalt_md5_rn(const char *prefix, unsigned long count, + const char *input, int size, char *output, int output_size) +{ + unsigned long value; + + (void) prefix; + + if (size < 3 || output_size < 3 + 4 + 1 || (count && count != 1000)) { + if (output_size > 0) output[0] = '\0'; + __set_errno((output_size < 3 + 4 + 1) ? ERANGE : EINVAL); + return NULL; + } + + output[0] = '$'; + output[1] = '1'; + output[2] = '$'; + value = (unsigned long)(unsigned char)input[0] | + ((unsigned long)(unsigned char)input[1] << 8) | + ((unsigned long)(unsigned char)input[2] << 16); + output[3] = _crypt_itoa64[value & 0x3f]; + output[4] = _crypt_itoa64[(value >> 6) & 0x3f]; + output[5] = _crypt_itoa64[(value >> 12) & 0x3f]; + output[6] = _crypt_itoa64[(value >> 18) & 0x3f]; + output[7] = '\0'; + + if (size >= 6 && output_size >= 3 + 4 + 4 + 1) { + value = (unsigned long)(unsigned char)input[3] | + ((unsigned long)(unsigned char)input[4] << 8) | + ((unsigned long)(unsigned char)input[5] << 16); + output[7] = _crypt_itoa64[value & 0x3f]; + output[8] = _crypt_itoa64[(value >> 6) & 0x3f]; + output[9] = _crypt_itoa64[(value >> 12) & 0x3f]; + output[10] = _crypt_itoa64[(value >> 18) & 0x3f]; + output[11] = '\0'; + } + + return output; +} diff --git a/src/util/crypto/crypt_blowfish/crypt_gensalt.h b/src/util/crypto/crypt_blowfish/crypt_gensalt.h new file mode 100644 index 000000000..457bbfe29 --- /dev/null +++ b/src/util/crypto/crypt_blowfish/crypt_gensalt.h @@ -0,0 +1,30 @@ +/* + * Written by Solar Designer in 2000-2011. + * No copyright is claimed, and the software is hereby placed in the public + * domain. In case this attempt to disclaim copyright and place the software + * in the public domain is deemed null and void, then the software is + * Copyright (c) 2000-2011 Solar Designer and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * See crypt_blowfish.c for more information. + */ + +#ifndef _CRYPT_GENSALT_H +#define _CRYPT_GENSALT_H + +extern unsigned char _crypt_itoa64[]; +extern char *_crypt_gensalt_traditional_rn(const char *prefix, + unsigned long count, + const char *input, int size, char *output, int output_size); +extern char *_crypt_gensalt_extended_rn(const char *prefix, + unsigned long count, + const char *input, int size, char *output, int output_size); +extern char *_crypt_gensalt_md5_rn(const char *prefix, unsigned long count, + const char *input, int size, char *output, int output_size); + +#endif diff --git a/src/util/crypto/crypt_blowfish/ow-crypt.h b/src/util/crypto/crypt_blowfish/ow-crypt.h new file mode 100644 index 000000000..2e4879426 --- /dev/null +++ b/src/util/crypto/crypt_blowfish/ow-crypt.h @@ -0,0 +1,43 @@ +/* + * Written by Solar Designer in 2000-2011. + * No copyright is claimed, and the software is hereby placed in the public + * domain. In case this attempt to disclaim copyright and place the software + * in the public domain is deemed null and void, then the software is + * Copyright (c) 2000-2011 Solar Designer and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * See crypt_blowfish.c for more information. + */ + +#ifndef _OW_CRYPT_H +#define _OW_CRYPT_H + +#ifndef __GNUC__ +#undef __const +#define __const const +#endif + +#ifndef __SKIP_GNU +extern char *crypt(__const char *key, __const char *setting); +extern char *crypt_r(__const char *key, __const char *setting, void *data); +#endif + +#ifndef __SKIP_OW +extern char *crypt_rn(__const char *key, __const char *setting, + void *data, int size); +extern char *crypt_ra(__const char *key, __const char *setting, + void **data, int *size); +extern char *crypt_gensalt(__const char *prefix, unsigned long count, + __const char *input, int size); +extern char *crypt_gensalt_rn(__const char *prefix, unsigned long count, + __const char *input, int size, char *output, int output_size); +extern char *crypt_gensalt_ra(__const char *prefix, unsigned long count, + __const char *input, int size); +#endif + +#endif diff --git a/src/util/crypto/crypt_blowfish/wrapper.c b/src/util/crypto/crypt_blowfish/wrapper.c new file mode 100644 index 000000000..b69ba7ae6 --- /dev/null +++ b/src/util/crypto/crypt_blowfish/wrapper.c @@ -0,0 +1,553 @@ +/* + * Written by Solar Designer in 2000-2014. + * No copyright is claimed, and the software is hereby placed in the public + * domain. In case this attempt to disclaim copyright and place the software + * in the public domain is deemed null and void, then the software is + * Copyright (c) 2000-2014 Solar Designer and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * See crypt_blowfish.c for more information. + */ + +#include +#include + +#include +#ifndef __set_errno +#define __set_errno(val) errno = (val) +#endif + +#ifdef TEST +#include +#include +#include +#include +#include +#include +#ifdef TEST_THREADS +#include +#endif +#endif + +#define CRYPT_OUTPUT_SIZE (7 + 22 + 31 + 1) +#define CRYPT_GENSALT_OUTPUT_SIZE (7 + 22 + 1) + +#if defined(__GLIBC__) && defined(_LIBC) +#define __SKIP_GNU +#endif +#include "ow-crypt.h" + +#include "crypt_blowfish.h" +#include "crypt_gensalt.h" + +#if defined(__GLIBC__) && defined(_LIBC) +/* crypt.h from glibc-crypt-2.1 will define struct crypt_data for us */ +#include "crypt.h" +extern char *__md5_crypt_r(const char *key, const char *salt, + char *buffer, int buflen); +/* crypt-entry.c needs to be patched to define __des_crypt_r rather than + * __crypt_r, and not define crypt_r and crypt at all */ +extern char *__des_crypt_r(const char *key, const char *salt, + struct crypt_data *data); +extern struct crypt_data _ufc_foobar; +#endif + +static int _crypt_data_alloc(void **data, int *size, int need) +{ + void *updated; + + if (*data && *size >= need) return 0; + + updated = realloc(*data, need); + + if (!updated) { +#ifndef __GLIBC__ + /* realloc(3) on glibc sets errno, so we don't need to bother */ + __set_errno(ENOMEM); +#endif + return -1; + } + +#if defined(__GLIBC__) && defined(_LIBC) + if (need >= sizeof(struct crypt_data)) + ((struct crypt_data *)updated)->initialized = 0; +#endif + + *data = updated; + *size = need; + + return 0; +} + +static char *_crypt_retval_magic(char *retval, const char *setting, + char *output, int size) +{ + if (retval) + return retval; + + if (_crypt_output_magic(setting, output, size)) + return NULL; /* shouldn't happen */ + + return output; +} + +#if defined(__GLIBC__) && defined(_LIBC) +/* + * Applications may re-use the same instance of struct crypt_data without + * resetting the initialized field in order to let crypt_r() skip some of + * its initialization code. Thus, it is important that our multiple hashing + * algorithms either don't conflict with each other in their use of the + * data area or reset the initialized field themselves whenever required. + * Currently, the hashing algorithms simply have no conflicts: the first + * field of struct crypt_data is the 128-byte large DES key schedule which + * __des_crypt_r() calculates each time it is called while the two other + * hashing algorithms use less than 128 bytes of the data area. + */ + +char *__crypt_rn(__const char *key, __const char *setting, + void *data, int size) +{ + if (setting[0] == '$' && setting[1] == '2') + return _crypt_blowfish_rn(key, setting, (char *)data, size); + if (setting[0] == '$' && setting[1] == '1') + return __md5_crypt_r(key, setting, (char *)data, size); + if (setting[0] == '$' || setting[0] == '_') { + __set_errno(EINVAL); + return NULL; + } + if (size >= sizeof(struct crypt_data)) + return __des_crypt_r(key, setting, (struct crypt_data *)data); + __set_errno(ERANGE); + return NULL; +} + +char *__crypt_ra(__const char *key, __const char *setting, + void **data, int *size) +{ + if (setting[0] == '$' && setting[1] == '2') { + if (_crypt_data_alloc(data, size, CRYPT_OUTPUT_SIZE)) + return NULL; + return _crypt_blowfish_rn(key, setting, (char *)*data, *size); + } + if (setting[0] == '$' && setting[1] == '1') { + if (_crypt_data_alloc(data, size, CRYPT_OUTPUT_SIZE)) + return NULL; + return __md5_crypt_r(key, setting, (char *)*data, *size); + } + if (setting[0] == '$' || setting[0] == '_') { + __set_errno(EINVAL); + return NULL; + } + if (_crypt_data_alloc(data, size, sizeof(struct crypt_data))) + return NULL; + return __des_crypt_r(key, setting, (struct crypt_data *)*data); +} + +char *__crypt_r(__const char *key, __const char *setting, + struct crypt_data *data) +{ + return _crypt_retval_magic( + __crypt_rn(key, setting, data, sizeof(*data)), + setting, (char *)data, sizeof(*data)); +} + +char *__crypt(__const char *key, __const char *setting) +{ + return _crypt_retval_magic( + __crypt_rn(key, setting, &_ufc_foobar, sizeof(_ufc_foobar)), + setting, (char *)&_ufc_foobar, sizeof(_ufc_foobar)); +} +#else +char *crypt_rn(const char *key, const char *setting, void *data, int size) +{ + return _crypt_blowfish_rn(key, setting, (char *)data, size); +} + +char *crypt_ra(const char *key, const char *setting, + void **data, int *size) +{ + if (_crypt_data_alloc(data, size, CRYPT_OUTPUT_SIZE)) + return NULL; + return _crypt_blowfish_rn(key, setting, (char *)*data, *size); +} + +char *crypt_r(const char *key, const char *setting, void *data) +{ + return _crypt_retval_magic( + crypt_rn(key, setting, data, CRYPT_OUTPUT_SIZE), + setting, (char *)data, CRYPT_OUTPUT_SIZE); +} + +char *crypt(const char *key, const char *setting) +{ + static char output[CRYPT_OUTPUT_SIZE]; + + return _crypt_retval_magic( + crypt_rn(key, setting, output, sizeof(output)), + setting, output, sizeof(output)); +} + +#define __crypt_gensalt_rn crypt_gensalt_rn +#define __crypt_gensalt_ra crypt_gensalt_ra +#define __crypt_gensalt crypt_gensalt +#endif + +char *__crypt_gensalt_rn(const char *prefix, unsigned long count, + const char *input, int size, char *output, int output_size) +{ + char *(*use)(const char *_prefix, unsigned long _count, + const char *_input, int _size, + char *_output, int _output_size); + + /* This may be supported on some platforms in the future */ + if (!input) { + __set_errno(EINVAL); + return NULL; + } + + if (!strncmp(prefix, "$2a$", 4) || !strncmp(prefix, "$2b$", 4) || + !strncmp(prefix, "$2y$", 4)) + use = _crypt_gensalt_blowfish_rn; + else + if (!strncmp(prefix, "$1$", 3)) + use = _crypt_gensalt_md5_rn; + else + if (prefix[0] == '_') + use = _crypt_gensalt_extended_rn; + else + if (!prefix[0] || + (prefix[0] && prefix[1] && + memchr(_crypt_itoa64, prefix[0], 64) && + memchr(_crypt_itoa64, prefix[1], 64))) + use = _crypt_gensalt_traditional_rn; + else { + __set_errno(EINVAL); + return NULL; + } + + return use(prefix, count, input, size, output, output_size); +} + +char *__crypt_gensalt_ra(const char *prefix, unsigned long count, + const char *input, int size) +{ + char output[CRYPT_GENSALT_OUTPUT_SIZE]; + char *retval; + + retval = __crypt_gensalt_rn(prefix, count, + input, size, output, sizeof(output)); + + if (retval) { + size_t len = 1 + strlen(retval); + char * dst = malloc(len); +#ifndef __GLIBC__ + /* malloc(3) on glibc sets errno, so we don't need to bother */ + if (!dst) + __set_errno(ENOMEM); +#endif + retval = memcpy(dst, retval, len); + } + + return retval; +} + +char *__crypt_gensalt(const char *prefix, unsigned long count, + const char *input, int size) +{ + static char output[CRYPT_GENSALT_OUTPUT_SIZE]; + + return __crypt_gensalt_rn(prefix, count, + input, size, output, sizeof(output)); +} + +#if defined(__GLIBC__) && defined(_LIBC) +weak_alias(__crypt_rn, crypt_rn) +weak_alias(__crypt_ra, crypt_ra) +weak_alias(__crypt_r, crypt_r) +weak_alias(__crypt, crypt) +weak_alias(__crypt_gensalt_rn, crypt_gensalt_rn) +weak_alias(__crypt_gensalt_ra, crypt_gensalt_ra) +weak_alias(__crypt_gensalt, crypt_gensalt) +weak_alias(crypt, fcrypt) +#endif + +#ifdef TEST +static const char *tests[][3] = { + {"$2a$05$CCCCCCCCCCCCCCCCCCCCC.E5YPO9kmyuRGyh0XouQYb4YMJKvyOeW", + "U*U"}, + {"$2a$05$CCCCCCCCCCCCCCCCCCCCC.VGOzA784oUp/Z0DY336zx7pLYAy0lwK", + "U*U*"}, + {"$2a$05$XXXXXXXXXXXXXXXXXXXXXOAcXxm9kjPGEMsLznoKqmqw7tc8WCx4a", + "U*U*U"}, + {"$2a$05$abcdefghijklmnopqrstuu5s2v8.iXieOjg/.AySBTTZIIVFJeBui", + "0123456789abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + "chars after 72 are ignored"}, + {"$2x$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e", + "\xa3"}, + {"$2x$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e", + "\xff\xff\xa3"}, + {"$2y$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e", + "\xff\xff\xa3"}, + {"$2a$05$/OK.fbVrR/bpIqNJ5ianF.nqd1wy.pTMdcvrRWxyiGL2eMz.2a85.", + "\xff\xff\xa3"}, + {"$2b$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e", + "\xff\xff\xa3"}, + {"$2y$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq", + "\xa3"}, + {"$2a$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq", + "\xa3"}, + {"$2b$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq", + "\xa3"}, + {"$2x$05$/OK.fbVrR/bpIqNJ5ianF.o./n25XVfn6oAPaUvHe.Csk4zRfsYPi", + "1\xa3" "345"}, + {"$2x$05$/OK.fbVrR/bpIqNJ5ianF.o./n25XVfn6oAPaUvHe.Csk4zRfsYPi", + "\xff\xa3" "345"}, + {"$2x$05$/OK.fbVrR/bpIqNJ5ianF.o./n25XVfn6oAPaUvHe.Csk4zRfsYPi", + "\xff\xa3" "34" "\xff\xff\xff\xa3" "345"}, + {"$2y$05$/OK.fbVrR/bpIqNJ5ianF.o./n25XVfn6oAPaUvHe.Csk4zRfsYPi", + "\xff\xa3" "34" "\xff\xff\xff\xa3" "345"}, + {"$2a$05$/OK.fbVrR/bpIqNJ5ianF.ZC1JEJ8Z4gPfpe1JOr/oyPXTWl9EFd.", + "\xff\xa3" "34" "\xff\xff\xff\xa3" "345"}, + {"$2y$05$/OK.fbVrR/bpIqNJ5ianF.nRht2l/HRhr6zmCp9vYUvvsqynflf9e", + "\xff\xa3" "345"}, + {"$2a$05$/OK.fbVrR/bpIqNJ5ianF.nRht2l/HRhr6zmCp9vYUvvsqynflf9e", + "\xff\xa3" "345"}, + {"$2a$05$/OK.fbVrR/bpIqNJ5ianF.6IflQkJytoRVc1yuaNtHfiuq.FRlSIS", + "\xa3" "ab"}, + {"$2x$05$/OK.fbVrR/bpIqNJ5ianF.6IflQkJytoRVc1yuaNtHfiuq.FRlSIS", + "\xa3" "ab"}, + {"$2y$05$/OK.fbVrR/bpIqNJ5ianF.6IflQkJytoRVc1yuaNtHfiuq.FRlSIS", + "\xa3" "ab"}, + {"$2x$05$6bNw2HLQYeqHYyBfLMsv/OiwqTymGIGzFsA4hOTWebfehXHNprcAS", + "\xd1\x91"}, + {"$2x$05$6bNw2HLQYeqHYyBfLMsv/O9LIGgn8OMzuDoHfof8AQimSGfcSWxnS", + "\xd0\xc1\xd2\xcf\xcc\xd8"}, + {"$2a$05$/OK.fbVrR/bpIqNJ5ianF.swQOIzjOiJ9GHEPuhEkvqrUyvWhEMx6", + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "chars after 72 are ignored as usual"}, + {"$2a$05$/OK.fbVrR/bpIqNJ5ianF.R9xrDjiycxMbQE2bp.vgqlYpW5wx2yy", + "\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55" + "\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55" + "\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55" + "\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55" + "\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55" + "\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55"}, + {"$2a$05$/OK.fbVrR/bpIqNJ5ianF.9tQZzcJfm3uj2NvJ/n5xkhpqLrMpWCe", + "\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff" + "\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff" + "\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff" + "\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff" + "\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff" + "\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff"}, + {"$2a$05$CCCCCCCCCCCCCCCCCCCCC.7uG0VCzI2bS7j6ymqJi9CdcdxiRTWNy", + ""}, + {"*0", "", "$2a$03$CCCCCCCCCCCCCCCCCCCCC."}, + {"*0", "", "$2a$32$CCCCCCCCCCCCCCCCCCCCC."}, + {"*0", "", "$2c$05$CCCCCCCCCCCCCCCCCCCCC."}, + {"*0", "", "$2z$05$CCCCCCCCCCCCCCCCCCCCC."}, + {"*0", "", "$2`$05$CCCCCCCCCCCCCCCCCCCCC."}, + {"*0", "", "$2{$05$CCCCCCCCCCCCCCCCCCCCC."}, + {"*1", "", "*0"}, + {NULL} +}; + +#define which tests[0] + +static volatile sig_atomic_t running; + +static void handle_timer(int signum) +{ + (void) signum; + running = 0; +} + +static void *run(void *arg) +{ + unsigned long count = 0; + int i = 0; + void *data = NULL; + int size = 0x12345678; + + do { + const char *hash = tests[i][0]; + const char *key = tests[i][1]; + const char *setting = tests[i][2]; + + if (!tests[++i][0]) + i = 0; + + if (setting && strlen(hash) < 30) /* not for benchmark */ + continue; + + if (strcmp(crypt_ra(key, hash, &data, &size), hash)) { + printf("%d: FAILED (crypt_ra/%d/%lu)\n", + (int)((char *)arg - (char *)0), i, count); + free(data); + return NULL; + } + count++; + } while (running); + + free(data); + return count + (char *)0; +} + +int main(void) +{ + struct itimerval it; + struct tms buf; + clock_t clk_tck, start_real, start_virtual, end_real, end_virtual; + unsigned long count; + void *data; + int size; + char *setting1, *setting2; + int i; +#ifdef TEST_THREADS + pthread_t t[TEST_THREADS]; + void *t_retval; +#endif + + data = NULL; + size = 0x12345678; + + for (i = 0; tests[i][0]; i++) { + const char *hash = tests[i][0]; + const char *key = tests[i][1]; + const char *setting = tests[i][2]; + const char *p; + int ok = !setting || strlen(hash) >= 30; + int o_size; + char s_buf[30], o_buf[61]; + if (!setting) { + memcpy(s_buf, hash, sizeof(s_buf) - 1); + s_buf[sizeof(s_buf) - 1] = 0; + setting = s_buf; + } + + __set_errno(0); + p = crypt(key, setting); + if ((!ok && !errno) || strcmp(p, hash)) { + printf("FAILED (crypt/%d)\n", i); + return 1; + } + + if (ok && strcmp(crypt(key, hash), hash)) { + printf("FAILED (crypt/%d)\n", i); + return 1; + } + + for (o_size = -1; o_size <= (int)sizeof(o_buf); o_size++) { + int ok_n = ok && o_size == (int)sizeof(o_buf); + const char *x = "abc"; + strcpy(o_buf, x); + if (o_size >= 3) { + x = "*0"; + if (setting[0] == '*' && setting[1] == '0') + x = "*1"; + } + __set_errno(0); + p = crypt_rn(key, setting, o_buf, o_size); + if ((ok_n && (!p || strcmp(p, hash))) || + (!ok_n && (!errno || p || strcmp(o_buf, x)))) { + printf("FAILED (crypt_rn/%d)\n", i); + return 1; + } + } + + __set_errno(0); + p = crypt_ra(key, setting, &data, &size); + if ((ok && (!p || strcmp(p, hash))) || + (!ok && (!errno || p || strcmp((char *)data, hash)))) { + printf("FAILED (crypt_ra/%d)\n", i); + return 1; + } + } + + setting1 = crypt_gensalt(which[0], 12, data, size); + if (!setting1 || strncmp(setting1, "$2a$12$", 7)) { + puts("FAILED (crypt_gensalt)\n"); + return 1; + } + + setting2 = crypt_gensalt_ra(setting1, 12, data, size); + if (strcmp(setting1, setting2)) { + puts("FAILED (crypt_gensalt_ra/1)\n"); + return 1; + } + + (*(char *)data)++; + setting1 = crypt_gensalt_ra(setting2, 12, data, size); + if (!strcmp(setting1, setting2)) { + puts("FAILED (crypt_gensalt_ra/2)\n"); + return 1; + } + + free(setting1); + free(setting2); + free(data); + +#if defined(_SC_CLK_TCK) || !defined(CLK_TCK) + clk_tck = sysconf(_SC_CLK_TCK); +#else + clk_tck = CLK_TCK; +#endif + + running = 1; + signal(SIGALRM, handle_timer); + + memset(&it, 0, sizeof(it)); + it.it_value.tv_sec = 5; + setitimer(ITIMER_REAL, &it, NULL); + + start_real = times(&buf); + start_virtual = buf.tms_utime + buf.tms_stime; + + count = (char *)run((char *)0) - (char *)0; + + end_real = times(&buf); + end_virtual = buf.tms_utime + buf.tms_stime; + if (end_virtual == start_virtual) end_virtual++; + + printf("%.1f c/s real, %.1f c/s virtual\n", + (float)count * clk_tck / (end_real - start_real), + (float)count * clk_tck / (end_virtual - start_virtual)); + +#ifdef TEST_THREADS + running = 1; + it.it_value.tv_sec = 60; + setitimer(ITIMER_REAL, &it, NULL); + start_real = times(&buf); + + for (i = 0; i < TEST_THREADS; i++) + if (pthread_create(&t[i], NULL, run, i + (char *)0)) { + perror("pthread_create"); + return 1; + } + + for (i = 0; i < TEST_THREADS; i++) { + if (pthread_join(t[i], &t_retval)) { + perror("pthread_join"); + continue; + } + if (!t_retval) continue; + count = (char *)t_retval - (char *)0; + end_real = times(&buf); + printf("%d: %.1f c/s real\n", i, + (float)count * clk_tck / (end_real - start_real)); + } +#endif + + return 0; +} +#endif diff --git a/src/util/crypto/crypt_blowfish/x86.S b/src/util/crypto/crypt_blowfish/x86.S new file mode 100644 index 000000000..b0f1cd2ef --- /dev/null +++ b/src/util/crypto/crypt_blowfish/x86.S @@ -0,0 +1,203 @@ +/* + * Written by Solar Designer in 1998-2010. + * No copyright is claimed, and the software is hereby placed in the public + * domain. In case this attempt to disclaim copyright and place the software + * in the public domain is deemed null and void, then the software is + * Copyright (c) 1998-2010 Solar Designer and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * See crypt_blowfish.c for more information. + */ + +#ifdef __i386__ + +#if defined(__OpenBSD__) && !defined(__ELF__) +#define UNDERSCORES +#define ALIGN_LOG +#endif + +#if defined(__CYGWIN32__) || defined(__MINGW32__) +#define UNDERSCORES +#endif + +#ifdef __DJGPP__ +#define UNDERSCORES +#define ALIGN_LOG +#endif + +#ifdef UNDERSCORES +#define _BF_body_r __BF_body_r +#endif + +#ifdef ALIGN_LOG +#define DO_ALIGN(log) .align (log) +#elif defined(DUMBAS) +#define DO_ALIGN(log) .align 1 << log +#else +#define DO_ALIGN(log) .align (1 << (log)) +#endif + +#define BF_FRAME 0x200 +#define ctx %esp + +#define BF_ptr (ctx) + +#define S(N, r) N+BF_FRAME(ctx,r,4) +#ifdef DUMBAS +#define P(N) 0x1000+N+N+N+N+BF_FRAME(ctx) +#else +#define P(N) 0x1000+4*N+BF_FRAME(ctx) +#endif + +/* + * This version of the assembly code is optimized primarily for the original + * Intel Pentium but is also careful to avoid partial register stalls on the + * Pentium Pro family of processors (tested up to Pentium III Coppermine). + * + * It is possible to do 15% faster on the Pentium Pro family and probably on + * many non-Intel x86 processors, but, unfortunately, that would make things + * twice slower for the original Pentium. + * + * An additional 2% speedup may be achieved with non-reentrant code. + */ + +#define L %esi +#define R %edi +#define tmp1 %eax +#define tmp1_lo %al +#define tmp2 %ecx +#define tmp2_hi %ch +#define tmp3 %edx +#define tmp3_lo %dl +#define tmp4 %ebx +#define tmp4_hi %bh +#define tmp5 %ebp + +.text + +#define BF_ROUND(L, R, N) \ + xorl L,tmp2; \ + xorl tmp1,tmp1; \ + movl tmp2,L; \ + shrl $16,tmp2; \ + movl L,tmp4; \ + movb tmp2_hi,tmp1_lo; \ + andl $0xFF,tmp2; \ + movb tmp4_hi,tmp3_lo; \ + andl $0xFF,tmp4; \ + movl S(0,tmp1),tmp1; \ + movl S(0x400,tmp2),tmp5; \ + addl tmp5,tmp1; \ + movl S(0x800,tmp3),tmp5; \ + xorl tmp5,tmp1; \ + movl S(0xC00,tmp4),tmp5; \ + addl tmp1,tmp5; \ + movl 4+P(N),tmp2; \ + xorl tmp5,R + +#define BF_ENCRYPT_START \ + BF_ROUND(L, R, 0); \ + BF_ROUND(R, L, 1); \ + BF_ROUND(L, R, 2); \ + BF_ROUND(R, L, 3); \ + BF_ROUND(L, R, 4); \ + BF_ROUND(R, L, 5); \ + BF_ROUND(L, R, 6); \ + BF_ROUND(R, L, 7); \ + BF_ROUND(L, R, 8); \ + BF_ROUND(R, L, 9); \ + BF_ROUND(L, R, 10); \ + BF_ROUND(R, L, 11); \ + BF_ROUND(L, R, 12); \ + BF_ROUND(R, L, 13); \ + BF_ROUND(L, R, 14); \ + BF_ROUND(R, L, 15); \ + movl BF_ptr,tmp5; \ + xorl L,tmp2; \ + movl P(17),L + +#define BF_ENCRYPT_END \ + xorl R,L; \ + movl tmp2,R + +DO_ALIGN(5) +.globl _BF_body_r +_BF_body_r: + movl 4(%esp),%eax + pushl %ebp + pushl %ebx + pushl %esi + pushl %edi + subl $BF_FRAME-8,%eax + xorl L,L + cmpl %esp,%eax + ja BF_die + xchgl %eax,%esp + xorl R,R + pushl %eax + leal 0x1000+BF_FRAME-4(ctx),%eax + movl 0x1000+BF_FRAME-4(ctx),tmp2 + pushl %eax + xorl tmp3,tmp3 +BF_loop_P: + BF_ENCRYPT_START + addl $8,tmp5 + BF_ENCRYPT_END + leal 0x1000+18*4+BF_FRAME(ctx),tmp1 + movl tmp5,BF_ptr + cmpl tmp5,tmp1 + movl L,-8(tmp5) + movl R,-4(tmp5) + movl P(0),tmp2 + ja BF_loop_P + leal BF_FRAME(ctx),tmp5 + xorl tmp3,tmp3 + movl tmp5,BF_ptr +BF_loop_S: + BF_ENCRYPT_START + BF_ENCRYPT_END + movl P(0),tmp2 + movl L,(tmp5) + movl R,4(tmp5) + BF_ENCRYPT_START + BF_ENCRYPT_END + movl P(0),tmp2 + movl L,8(tmp5) + movl R,12(tmp5) + BF_ENCRYPT_START + BF_ENCRYPT_END + movl P(0),tmp2 + movl L,16(tmp5) + movl R,20(tmp5) + BF_ENCRYPT_START + addl $32,tmp5 + BF_ENCRYPT_END + leal 0x1000+BF_FRAME(ctx),tmp1 + movl tmp5,BF_ptr + cmpl tmp5,tmp1 + movl P(0),tmp2 + movl L,-8(tmp5) + movl R,-4(tmp5) + ja BF_loop_S + movl 4(%esp),%esp + popl %edi + popl %esi + popl %ebx + popl %ebp + ret + +BF_die: +/* Oops, need to re-compile with a larger BF_FRAME. */ + hlt + jmp BF_die + +#endif + +#if defined(__ELF__) && defined(__linux__) +.section .note.GNU-stack,"",@progbits +#endif diff --git a/src/util/crypto/crypto.c b/src/util/crypto/crypto.c new file mode 100644 index 000000000..75129a826 --- /dev/null +++ b/src/util/crypto/crypto.c @@ -0,0 +1,205 @@ +/* + * bcrypt wrapper library + * + * Written in 2011, 2013, 2014, 2015 by Ricardo Garcia + * + * To the extent possible under law, the author(s) have dedicated all copyright + * and related and neighboring rights to this software to the public domain + * worldwide. This software is distributed without any warranty. + * + * You should have received a copy of the CC0 Public Domain Dedication along + * with this software. If not, see + * . + */ +#include +#include +#include +#include +#include + +#ifdef WIN32 +#include +#include +#else +#include +#endif + +#include "crypto.h" +#include "crypt_blowfish/ow-crypt.h" + +#define RANDBYTES (16) + +#ifndef WIN32 +static int try_close(int fd) +{ + int ret; + for (;;) { + errno = 0; + ret = close(fd); + if (ret == -1 && errno == EINTR) + continue; + break; + } + return ret; +} + +static int try_read(int fd, char *out, size_t count) +{ + size_t total; + ssize_t partial; + + total = 0; + while (total < count) + { + for (;;) { + errno = 0; + partial = read(fd, out + total, count - total); + if (partial == -1 && errno == EINTR) + continue; + break; + } + + if (partial < 1) + return -1; + + total += partial; + } + + return 0; +} +#endif +/* + * This is a best effort implementation. Nothing prevents a compiler from + * optimizing this function and making it vulnerable to timing attacks, but + * this method is commonly used in crypto libraries like NaCl. + * + * Return value is zero if both strings are equal and nonzero otherwise. +*/ +static int timing_safe_strcmp(const char *str1, const char *str2) +{ + const unsigned char *u1; + const unsigned char *u2; + int ret; + int i; + + int len1 = strlen(str1); + int len2 = strlen(str2); + + /* In our context both strings should always have the same length + * because they will be hashed passwords. */ + if (len1 != len2) + return 1; + + /* Force unsigned for bitwise operations. */ + u1 = (const unsigned char *)str1; + u2 = (const unsigned char *)str2; + + ret = 0; + for (i = 0; i < len1; ++i) + ret |= (u1[i] ^ u2[i]); + + return ret; +} + +int bcrypt_gensalt(int factor, char salt[BCRYPT_HASHSIZE]) +{ + char input[RANDBYTES]; + int workf; + char *aux; + +#ifdef WIN32 + BCryptGenRandom(NULL, input, RANDBYTES, BCRYPT_USE_SYSTEM_PREFERRED_RNG); +#else + int fd; + fd = open("/dev/urandom", O_RDONLY); + if (fd == -1) + return 1; + + if (try_read(fd, input, RANDBYTES) != 0) { + if (try_close(fd) != 0) + return 4; + return 2; + } + + if (try_close(fd) != 0) + return 3; +#endif + /* Generate salt. */ + workf = (factor < 4 || factor > 31)?12:factor; + aux = crypt_gensalt_rn("$2a$", workf, input, RANDBYTES, + salt, BCRYPT_HASHSIZE); + return (aux == NULL)?5:0; +} + +int bcrypt_hashpw(const char *passwd, const char salt[BCRYPT_HASHSIZE], char hash[BCRYPT_HASHSIZE]) +{ + char *aux; + aux = crypt_rn(passwd, salt, hash, BCRYPT_HASHSIZE); + return (aux == NULL)?1:0; +} + +int bcrypt_checkpw(const char *passwd, const char hash[BCRYPT_HASHSIZE]) +{ + int ret; + char outhash[BCRYPT_HASHSIZE]; + + ret = bcrypt_hashpw(passwd, hash, outhash); + if (ret != 0) + return -1; + + return timing_safe_strcmp(hash, outhash); +} + +#ifdef TEST_BCRYPT +#include +#include +#include +#include + +int main(void) +{ + clock_t before; + clock_t after; + char salt[BCRYPT_HASHSIZE]; + char hash[BCRYPT_HASHSIZE]; + int ret; + + const char pass[] = "hi,mom"; + const char hash1[] = "$2a$10$VEVmGHy4F4XQMJ3eOZJAUeb.MedU0W10pTPCuf53eHdKJPiSE8sMK"; + const char hash2[] = "$2a$10$3F0BVk5t8/aoS.3ddaB3l.fxg5qvafQ9NybxcpXLzMeAt.nVWn.NO"; + + ret = bcrypt_gensalt(12, salt); + assert(ret == 0); + printf("Generated salt: %s\n", salt); + before = clock(); + ret = bcrypt_hashpw("testtesttest", salt, hash); + assert(ret == 0); + after = clock(); + printf("Hashed password: %s\n", hash); + printf("Time taken: %f seconds\n", + (double)(after - before) / CLOCKS_PER_SEC); + + ret = bcrypt_hashpw(pass, hash1, hash); + assert(ret == 0); + printf("First hash check: %s\n", (strcmp(hash1, hash) == 0)?"OK":"FAIL"); + ret = bcrypt_hashpw(pass, hash2, hash); + assert(ret == 0); + printf("Second hash check: %s\n", (strcmp(hash2, hash) == 0)?"OK":"FAIL"); + + before = clock(); + ret = (bcrypt_checkpw(pass, hash1) == 0); + after = clock(); + printf("First hash check with bcrypt_checkpw: %s\n", ret?"OK":"FAIL"); + printf("Time taken: %f seconds\n", + (double)(after - before) / CLOCKS_PER_SEC); + + before = clock(); + ret = (bcrypt_checkpw(pass, hash2) == 0); + after = clock(); + printf("Second hash check with bcrypt_checkpw: %s\n", ret?"OK":"FAIL"); + printf("Time taken: %f seconds\n", + (double)(after - before) / CLOCKS_PER_SEC); + + return 0; +} +#endif diff --git a/src/util/crypto/crypto.h b/src/util/crypto/crypto.h new file mode 100644 index 000000000..e45b3ca13 --- /dev/null +++ b/src/util/crypto/crypto.h @@ -0,0 +1,97 @@ +#ifndef BCRYPT_H_ +#define BCRYPT_H_ +/* + * bcrypt wrapper library + * + * Written in 2011, 2013, 2014, 2015 by Ricardo Garcia + * + * To the extent possible under law, the author(s) have dedicated all copyright + * and related and neighboring rights to this software to the public domain + * worldwide. This software is distributed without any warranty. + * + * You should have received a copy of the CC0 Public Domain Dedication along + * with this software. If not, see + * . + */ + +#define BCRYPT_HASHSIZE (64) + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This function expects a work factor between 4 and 31 and a char array to + * store the resulting generated salt. The char array should typically have + * BCRYPT_HASHSIZE bytes at least. If the provided work factor is not in the + * previous range, it will default to 12. + * + * The return value is zero if the salt could be correctly generated and + * nonzero otherwise. + * + */ +int bcrypt_gensalt(int workfactor, char salt[BCRYPT_HASHSIZE]); + +/* + * This function expects a password to be hashed, a salt to hash the password + * with and a char array to leave the result. Both the salt and the hash + * parameters should have room for BCRYPT_HASHSIZE characters at least. + * + * It can also be used to verify a hashed password. In that case, provide the + * expected hash in the salt parameter and verify the output hash is the same + * as the input hash. However, to avoid timing attacks, it's better to use + * bcrypt_checkpw when verifying a password. + * + * The return value is zero if the password could be hashed and nonzero + * otherwise. + */ +int bcrypt_hashpw(const char *passwd, const char salt[BCRYPT_HASHSIZE], + char hash[BCRYPT_HASHSIZE]); + +/* + * This function expects a password and a hash to verify the password against. + * The internal implementation is tuned to avoid timing attacks. + * + * The return value will be -1 in case of errors, zero if the provided password + * matches the given hash and greater than zero if no errors are found and the + * passwords don't match. + * + */ +int bcrypt_checkpw(const char *passwd, const char hash[BCRYPT_HASHSIZE]); + +/* + * Brief Example + * ------------- + * + * Hashing a password: + * + * char salt[BCRYPT_HASHSIZE]; + * char hash[BCRYPT_HASHSIZE]; + * int ret; + * + * ret = bcrypt_gensalt(12, salt); + * assert(ret == 0); + * ret = bcrypt_hashpw("thepassword", salt, hash); + * assert(ret == 0); + * + * + * Verifying a password: + * + * int ret; + * + * ret = bcrypt_checkpw("thepassword", "expectedhash"); + * assert(ret != -1); + * + * if (ret == 0) { + * printf("The password matches\n"); + * } else { + * printf("The password does NOT match\n"); + * } + * + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/util/filereader.c b/src/util/filereader.c index e477b445c..c4a3b56cc 100644 --- a/src/util/filereader.c +++ b/src/util/filereader.c @@ -39,150 +39,6 @@ static int eatwhite(const char *ptr, size_t * total_size) return ret; } -static const char *getbuf_latin1(FILE * F) -{ - bool cont = false; - char quote = 0; - bool comment = false; - char *cp = fbuf; - char *tail = lbuf + MAXLINE - 2; - - tail[1] = '@'; /* if this gets overwritten by fgets then the line was very long. */ - do { - const char *bp = fgets(lbuf, MAXLINE, F); - - if (bp == NULL) - return NULL; - while (*bp && isspace(*(unsigned char *)bp)) - ++bp; /* eatwhite */ - - comment = (bool)(comment && cont); - quote = (bool)(quote && cont); - - if (tail[1] == 0) { - /* we read he maximum number of bytes! */ - if (tail[0] != '\n') { - /* it wasn't enough space to finish the line, eat the rest */ - for (;;) { - tail[1] = '@'; - bp = fgets(lbuf, MAXLINE, F); - if (bp == NULL) - return NULL; - if (tail[1]) { - /* read enough this time to end the line */ - break; - } - } - comment = false; - cont = false; - bp = NULL; - continue; - } - else { - tail[1] = '@'; - } - } - cont = false; - while (*bp && cp < fbuf + MAXLINE) { - int c = *(unsigned char *)bp; - - if (c == '\n' || c == '\r') { - /* line breaks, shmine breaks */ - break; - } - if (c == COMMENT_CHAR && !quote) { - /* comment begins. we need to keep going, to look for CONTINUE_CHAR */ - comment = true; - ++bp; - continue; - } - if (!comment && (c == '"' || c == '\'')) { - if (quote == c) { - quote = 0; - if (cp < fbuf + MAXLINE) - *cp++ = *bp; - ++bp; - continue; - } - else if (!quote) { - quote = *bp++; - if (cp < fbuf + MAXLINE) - *cp++ = quote; - continue; - } - } - - if (iscntrl(c)) { - if (!comment && cp < fbuf + MAXLINE) { - *cp++ = isspace(c) ? ' ' : '?'; - } - ++bp; - continue; - } - else if (isspace(c)) { - if (!quote) { - ++bp; - while (*bp && isspace(*(unsigned char *)bp)) - ++bp; /* eatwhite */ - if (!comment && *bp && *bp != COMMENT_CHAR && cp < fbuf + MAXLINE) - *(cp++) = ' '; - } - else if (!comment && cp + 1 <= fbuf + MAXLINE) { - *(cp++) = *(bp++); - } - else { - ++bp; - } - continue; - } - else if (c == CONTINUE_CHAR) { - const char *handle_end = ++bp; - while (*handle_end && isspace(*(unsigned char *)handle_end)) - ++handle_end; /* eatwhite */ - if (*handle_end == '\0') { - bp = handle_end; - cont = true; - continue; - } - if (comment) { - ++bp; - continue; - } - } - else if (comment) { - ++bp; - continue; - } - - if (c < 0x80) { - if (cp + 1 <= fbuf + MAXLINE) { - *(cp++) = *(bp++); - } - } - else { - char inbuf = (char)c; - size_t inbytes = 1; - size_t outbytes = MAXLINE - (cp - fbuf); - int ret = unicode_latin1_to_utf8(cp, &outbytes, &inbuf, &inbytes); - if (ret > 0) - cp += ret; - else { - log_error("input data was not iso-8859-1! assuming utf-8\n"); - return NULL; - } - - ++bp; - continue; - } - } - if (cp == fbuf + MAXLINE) { - --cp; - } - *cp = 0; - } while (cont || cp == fbuf); - return fbuf; -} - static const char *getbuf_utf8(FILE * F) { bool cont = false; @@ -202,8 +58,8 @@ static const char *getbuf_utf8(FILE * F) eatwhite(bp, &white); /* decoding errors will get caught later on, don't have to check */ bp += white; - comment = (bool)(comment && cont); - quote = (bool)(quote && cont); + comment = (comment && cont); + quote = (quote && cont); if (tail[1] == 0) { /* we read the maximum number of bytes! */ @@ -336,9 +192,7 @@ static const char *getbuf_utf8(FILE * F) return fbuf; } -const char *getbuf(FILE * F, int encoding) +const char *getbuf(FILE * F) { - if (encoding == ENCODING_UTF8) - return getbuf_utf8(F); - return getbuf_latin1(F); + return getbuf_utf8(F); } diff --git a/src/util/filereader.h b/src/util/filereader.h index eb09d14e1..a80afa65f 100644 --- a/src/util/filereader.h +++ b/src/util/filereader.h @@ -15,10 +15,7 @@ extern "C" { #endif -#define ENCODING_UTF8 0 -#define ENCODING_LATIN1 1 - - const char *getbuf(FILE *, int encoding); + const char *getbuf(FILE *); #ifdef __cplusplus } diff --git a/src/keyword.c b/src/util/keyword.c similarity index 96% rename from src/keyword.c rename to src/util/keyword.c index 48726bcbc..e2b5b4775 100644 --- a/src/keyword.c +++ b/src/util/keyword.c @@ -15,7 +15,7 @@ const char * keyword(keyword_t kwd) { static char result[32]; /* FIXME: static return value */ - if (kwd==NOKEYWORD) { + if (kwd==NOKEYWORD || keywords[kwd] == NULL) { return NULL; } if (!result[0]) { @@ -43,7 +43,7 @@ void init_keywords(const struct locale *lang) { keyword_t findkeyword(const char *s) { int i; for (i = 0; i != MAXKEYWORDS; ++i) { - if (strcmp(s, keywords[i]) == 0) { + if (keywords[i] && (strcmp(s, keywords[i]) == 0)) { return (keyword_t)i; } } @@ -94,7 +94,7 @@ const char *keywords[MAXKEYWORDS] = { "work", "attack", "steal", - "besiege", + NULL, "name", "use", "describe", diff --git a/src/keyword.h b/src/util/keyword.h similarity index 97% rename from src/keyword.h rename to src/util/keyword.h index 6e4832708..7bb11c485 100644 --- a/src/keyword.h +++ b/src/util/keyword.h @@ -1,7 +1,6 @@ #ifndef H_KEYWORD_H #define H_KEYWORD_H -#include "kernel/types.h" #include #ifdef __cplusplus @@ -17,7 +16,7 @@ extern "C" K_WORK, K_ATTACK, K_STEAL, - K_BESIEGE, + K_BESIEGE_UNUSED, K_NAME, K_USE, K_DISPLAY, diff --git a/src/keyword.test.c b/src/util/keyword.test.c similarity index 100% rename from src/keyword.test.c rename to src/util/keyword.test.c diff --git a/src/util/language.c b/src/util/language.c index 77a7d2a4e..afc9d01d0 100644 --- a/src/util/language.c +++ b/src/util/language.c @@ -353,29 +353,20 @@ void *get_translation(const struct locale *lang, const char *str, int index) { return NULL; } -void locale_foreach(void(*callback)(const struct locale *, const char *)) { - const locale * lang; - for (lang = locales; lang; lang = lang->next) { - callback(lang, lang->name); - } -} - const char *localenames[] = { "de", "en", NULL }; -extern void init_locale(struct locale *lang); - static int locale_init = 0; -void init_locales(void) +void init_locales(locale_handler init) { locale * lang; if (locale_init) return; assert(locales); - for (lang = locales; lang; lang = lang->next) { - init_locale(lang); + for (lang = locales; lang; lang = nextlocale(lang)) { + init(lang); } locale_init = 1; } diff --git a/src/util/language.h b/src/util/language.h index f269a5f06..735fd4a95 100644 --- a/src/util/language.h +++ b/src/util/language.h @@ -39,7 +39,8 @@ extern "C" { /** managing multiple locales: **/ struct locale *get_locale(const char *name); struct locale *get_or_create_locale(const char *key); - void init_locales(void); + typedef void(*locale_handler)(struct locale *lang); + void init_locales(locale_handler callback); void free_locales(void); void reset_locales(void); @@ -57,7 +58,6 @@ extern "C" { void make_locales(const char *str); - void locale_foreach(void(*callback)(const struct locale *lang, const char *name)); void po_write_msg(FILE *F, const char *id, const char *str, const char *ctxt); #define LOC(lang, s) (lang?locale_string(lang, s, true):s) diff --git a/src/util/log.c b/src/util/log.c index 0a24503e1..fd50ec700 100644 --- a/src/util/log.c +++ b/src/util/log.c @@ -12,8 +12,9 @@ without prior permission by the authors of Eressea. #include #include "log.h" -#include "unicode.h" +#include "path.h" #include "strings.h" +#include "unicode.h" #include diff --git a/src/util/message.c b/src/util/message.c index 82258e02f..47a8eb7af 100644 --- a/src/util/message.c +++ b/src/util/message.c @@ -86,13 +86,7 @@ static void mt_register(message_type * mtype) { message_type *mt_create(message_type * mtype, const char *args[], int nparameters) { - if (args != NULL && args[nparameters]) { - /* count the number of parameters */ - do { - ++nparameters; - } while (args[nparameters]); - } - if (nparameters > 0) { + if (args && nparameters > 0) { int i; mtype->nparameters = nparameters; mtype->pnames = (char **)malloc(sizeof(char *) * nparameters); diff --git a/src/util/order_parser.c b/src/util/order_parser.c new file mode 100644 index 000000000..21268f163 --- /dev/null +++ b/src/util/order_parser.c @@ -0,0 +1,287 @@ +#ifdef _MSC_VER +#include +#endif + +#include "order_parser.h" + +#include +#include +#include +#include + +struct OrderParserStruct { + void *m_userData; + char *m_buffer; + char *m_bufferPtr; + size_t m_bufferSize; + const char *m_bufferEnd; + OP_OrderHandler m_orderHandler; + enum OP_Error m_errorCode; + int m_lineNumber; +}; + +enum OP_Error OP_GetErrorCode(OP_Parser parser) { + return parser->m_errorCode; +} + +void OP_SetOrderHandler(OP_Parser parser, OP_OrderHandler handler) { + parser->m_orderHandler = handler; +} + +void OP_SetUserData(OP_Parser parser, void *userData) { + parser->m_userData = userData; +} + +static void buffer_free(OP_Parser parser) +{ + /* TODO: recycle buffers, reduce mallocs. */ + free(parser->m_buffer); + parser->m_bufferSize = 0; + parser->m_bufferEnd = parser->m_bufferPtr = parser->m_buffer = NULL; +} + +void OP_ParserReset(OP_Parser parser) { + parser->m_lineNumber = 1; + buffer_free(parser); +} + + +OP_Parser OP_ParserCreate(void) +{ + OP_Parser parser = calloc(1, sizeof(struct OrderParserStruct)); + OP_ParserReset(parser); + return parser; +} + +void OP_ParserFree(OP_Parser parser) { + free(parser->m_buffer); + free(parser); +} + +static enum OP_Error buffer_append(OP_Parser parser, const char *s, int len) +{ + size_t total = len + 1; + size_t remain = parser->m_bufferEnd - parser->m_bufferPtr; + total += remain; + if (remain > 0) { + /* there is remaining data in the buffer, should we move it to the front? */ + if (total <= parser->m_bufferSize) { + /* reuse existing buffer */ + memmove(parser->m_buffer, parser->m_bufferPtr, remain); + memcpy(parser->m_buffer + remain, s, len); + parser->m_buffer[total - 1] = '\0'; + parser->m_bufferPtr = parser->m_buffer; + parser->m_bufferEnd = parser->m_bufferPtr + total - 1; + return OP_ERROR_NONE; + } + } + else if (parser->m_bufferPtr >= parser->m_bufferEnd) { + buffer_free(parser); + } + + if (parser->m_buffer == NULL) { + parser->m_bufferSize = len + 1; + parser->m_buffer = malloc(parser->m_bufferSize); + if (!parser->m_buffer) { + return OP_ERROR_NO_MEMORY; + } + memcpy(parser->m_buffer, s, len); + parser->m_buffer[len] = '\0'; + parser->m_bufferPtr = parser->m_buffer; + parser->m_bufferEnd = parser->m_buffer + len; + } + else { + char * buffer; + /* TODO: recycle buffers, reduce mallocs. */ + if (parser->m_bufferSize < total) { + parser->m_bufferSize = total; + buffer = malloc(parser->m_bufferSize); + if (!buffer) { + return OP_ERROR_NO_MEMORY; + } + memcpy(buffer, parser->m_bufferPtr, total - len - 1); + memcpy(buffer + total - len - 1, s, len); + free(parser->m_buffer); + parser->m_buffer = buffer; + } + else { + memcpy(parser->m_buffer, parser->m_bufferPtr, total - len); + memcpy(parser->m_buffer + total - len, s, len); + } + parser->m_buffer[total - 1] = '\0'; + parser->m_bufferPtr = parser->m_buffer; + parser->m_bufferEnd = parser->m_buffer + total - 1; + } + return OP_ERROR_NONE; +} + +static char *skip_spaces(char *pos) { + char *next; + for (next = pos; *next && *next != '\n'; ++next) { + wint_t wch = *(unsigned char *)next; + /* TODO: handle unicode whitespace */ + if (!iswspace(wch)) break; + } + return next; +} + +static enum OP_Error handle_line(OP_Parser parser) { + if (parser->m_orderHandler) { + char * str = skip_spaces(parser->m_bufferPtr); + if (*str) { + parser->m_orderHandler(parser->m_userData, str); + } + } + return OP_ERROR_NONE; +} + +static enum OP_Status parse_buffer(OP_Parser parser, int isFinal) +{ + char * pos = strpbrk(parser->m_bufferPtr, "\\;\n"); + while (pos) { + enum OP_Error code; + size_t len = pos - parser->m_bufferPtr; + char *next; + int continue_comment = 0; + + switch (*pos) { + case '\n': + *pos = '\0'; + code = handle_line(parser); + ++parser->m_lineNumber; + if (code != OP_ERROR_NONE) { + parser->m_errorCode = code; + return OP_STATUS_ERROR; + } + parser->m_bufferPtr = pos + 1; + pos = strpbrk(parser->m_bufferPtr, "\\;\n"); + break; + case '\\': + /* if this is the last non-space before the line break, then lines need to be joined */ + next = skip_spaces(pos + 1); + if (*next == '\n') { + ptrdiff_t shift = (next + 1 - pos); + assert(shift > 0); + memmove(parser->m_bufferPtr + shift, parser->m_bufferPtr, len); + parser->m_bufferPtr += shift; + pos = strpbrk(next + 1, "\\;\n"); + ++parser->m_lineNumber; + } + else { + /* this is not multi-line input yet, so do nothing */ + if (pos[1] == '\0') { + /* end of available input */ + if (isFinal) { + /* input ends on a pointless backslash, kill it */ + pos[0] = '\0'; + pos = NULL; + } + else { + /* backslash is followed by data that we do not know */ + pos = NULL; + } + } + else { + pos = strpbrk(pos + 1, "\\;\n"); + } + } + break; + case ';': + /* the current line ends in a comment */ + *pos++ = '\0'; + handle_line(parser); + /* find the end of the comment so we can skip it. + * obs: multi-line comments are possible with a backslash. */ + do { + next = strpbrk(pos, "\\\n"); + if (next) { + if (*next == '\n') { + /* no more lines in this comment, we're done: */ + ++parser->m_lineNumber; + break; /* exit loop */ + } + else { + /* is this backslash the final character? */ + next = skip_spaces(next + 1); + if (*next == '\n') { + /* we have a multi-line comment! */ + pos = next + 1; + ++parser->m_lineNumber; + } + else if (*next == '\0') { + /* cannot find the EOL char yet, stream is dry. keep ; and \ */ + continue_comment = 2; + } + else { + /* keep looking for a backslash */ + pos = next; + } + } + } + } while (next && *next); + + if (!next) { + /* we exhausted the buffer before we finished the line */ + if (isFinal) { + /* this comment was at the end of the file, it just has no newline. done! */ + return OP_STATUS_OK; + } + else { + /* there is more of this line in the next buffer, save the semicolon */ + continue_comment = 1; + } + } + else { + if (*next) { + /* end comment parsing, begin parsing a new line */ + pos = next + 1; + continue_comment = 0; + } + else if (!continue_comment) { + /* reached end of input naturally, need more data to finish */ + continue_comment = 1; + } + } + + if (continue_comment) { + ptrdiff_t skip = parser->m_bufferEnd - parser->m_bufferPtr; + assert(skip >= continue_comment); + if (skip >= continue_comment) { + /* should always be true */ + parser->m_bufferPtr += (skip - continue_comment); + parser->m_bufferPtr[0] = ';'; + } + if (continue_comment == 2) { + parser->m_bufferPtr[1] = '\\'; + } + continue_comment = 0; + return OP_STATUS_OK; + } + /* continue the outer loop */ + parser->m_bufferPtr = pos; + pos = strpbrk(pos, "\\;\n"); + break; + default: + parser->m_errorCode = OP_ERROR_SYNTAX; + return OP_STATUS_ERROR; + } + } + if (isFinal && parser->m_bufferPtr < parser->m_bufferEnd) { + /* this line ends without a line break */ + handle_line(parser); + } + return OP_STATUS_OK; +} + +enum OP_Status OP_Parse(OP_Parser parser, const char *s, int len, int isFinal) +{ + enum OP_Error code; + + code = buffer_append(parser, s, len); + if (code != OP_ERROR_NONE) { + parser->m_errorCode = code; + return OP_STATUS_ERROR; + } + + return parse_buffer(parser, isFinal); +} diff --git a/src/util/order_parser.h b/src/util/order_parser.h new file mode 100644 index 000000000..159fd6594 --- /dev/null +++ b/src/util/order_parser.h @@ -0,0 +1,42 @@ +#pragma once +/* + * +-------------------+ Christian Schlittchen + * | | Enno Rehling + * | Eressea PBEM host | Katja Zedel + * | (c) 1998 - 2007 | + * | | This program may not be used, modified or distributed + * +-------------------+ without prior permission by the authors of Eressea. + * + */ + +#ifndef UTIL_ORDER_PARSER_H +#define UTIL_ORDER_PARSER_H + +#include +#include + +struct OrderParserStruct; +typedef struct OrderParserStruct *OP_Parser; + +enum OP_Status { + OP_STATUS_ERROR = 0, + OP_STATUS_OK = 1 +}; + +enum OP_Error { + OP_ERROR_NONE, + OP_ERROR_NO_MEMORY, + OP_ERROR_SYNTAX +}; + +typedef void(*OP_OrderHandler) (void *userData, const char *str); + +OP_Parser OP_ParserCreate(void); +void OP_ParserFree(OP_Parser parser); +void OP_ParserReset(OP_Parser parser); +enum OP_Status OP_Parse(OP_Parser parser, const char *s, int len, int isFinal); +void OP_SetOrderHandler(OP_Parser parser, OP_OrderHandler handler); +void OP_SetUserData(OP_Parser parser, void *userData); +enum OP_Error OP_GetErrorCode(OP_Parser parser); + +#endif diff --git a/src/util/order_parser.test.c b/src/util/order_parser.test.c new file mode 100644 index 000000000..d43f661fb --- /dev/null +++ b/src/util/order_parser.test.c @@ -0,0 +1,132 @@ +#ifdef _MSC_VER +#include +#endif + +#include "order_parser.h" +#include "strings.h" + +#include + +#include + +static void test_parse_noop(CuTest *tc) { + OP_Parser parser; + parser = OP_ParserCreate(); + CuAssertPtrNotNull(tc, parser); + CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Hello World", 11, 1)); + OP_ParserFree(parser); +} + +static void copy_line(void *udata, const char *str) { + char *dst = (char *)udata; + if (dst) { + strcpy(dst, str); + } +} + +static void test_parse_orders(CuTest *tc) { + OP_Parser parser; + char lastline[1024]; + + parser = OP_ParserCreate(); + OP_SetUserData(parser, lastline); + OP_SetOrderHandler(parser, copy_line); + CuAssertPtrNotNull(tc, parser); + + lastline[0] = 0; + CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Hello World", 11, 1)); + CuAssertStrEquals(tc, "Hello World", lastline); + OP_ParserReset(parser); + + lastline[0] = 0; + CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Error;\nHello World", 18, 1)); + CuAssertStrEquals(tc, "Hello World", lastline); + OP_ParserReset(parser); + + lastline[0] = 0; + CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Hello World;\\\nError", 19, 1)); + CuAssertStrEquals(tc, "Hello World", lastline); + OP_ParserReset(parser); + + lastline[0] = 0; + CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Hello World;\\", 13, 0)); + CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "\nError", 6, 1)); + CuAssertStrEquals(tc, "Hello World", lastline); + OP_ParserReset(parser); + + lastline[0] = 0; + CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Hello \\", 7, 0)); + CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "\nWorld", 6, 1)); + CuAssertStrEquals(tc, "Hello World", lastline); + OP_ParserReset(parser); + + lastline[0] = 0; + CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Hello World\n", 12, 1)); + CuAssertStrEquals(tc, "Hello World", lastline); + OP_ParserReset(parser); + + lastline[0] = 0; + CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Hello\\\n World", 13, 1)); + CuAssertStrEquals(tc, "Hello World", lastline); + OP_ParserReset(parser); + + lastline[0] = 0; + CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Hello;World", 11, 1)); + CuAssertStrEquals(tc, "Hello", lastline); + OP_ParserReset(parser); + + lastline[0] = 0; + CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Hello\\World", 11, 1)); + CuAssertStrEquals(tc, "Hello\\World", lastline); + OP_ParserReset(parser); + + lastline[0] = 0; + CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, ";\n", 2, 0)); + CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Hello World", 11, 1)); + CuAssertStrEquals(tc, "Hello World", lastline); + OP_ParserReset(parser); + + lastline[0] = 0; + CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, ";Hello \\", 8, 0)); + CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "\nWorld\n", 7, 0)); + CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Enno", 4, 1)); + CuAssertStrEquals(tc, "Enno", lastline); + OP_ParserReset(parser); + + lastline[0] = 0; + CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, ";Hello", 6, 0)); + CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "World\n", 6, 0)); + CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Enno", 4, 1)); + CuAssertStrEquals(tc, "Enno", lastline); + OP_ParserReset(parser); + + lastline[0] = 0; + CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Hello\\World \\", 14, 1)); + CuAssertStrEquals(tc, "Hello\\World ", lastline); + OP_ParserReset(parser); + + lastline[0] = 0; + CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Hello\n", 6, 0)); + CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "World\n", 6, 1)); + CuAssertStrEquals(tc, "World", lastline); + OP_ParserReset(parser); + + lastline[0] = 0; + CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Hello\n", 6, 0)); + CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "World\n", 6, 1)); + CuAssertStrEquals(tc, "World", lastline); + OP_ParserReset(parser); + lastline[0] = 0; + CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Hello \\", 7, 0)); + CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "\nWorld", 6, 1)); + CuAssertStrEquals(tc, "Hello World", lastline); + OP_ParserFree(parser); +} + +CuSuite *get_order_parser_suite(void) +{ + CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_parse_noop); + SUITE_ADD_TEST(suite, test_parse_orders); + return suite; +} diff --git a/src/util/param.c b/src/util/param.c new file mode 100644 index 000000000..31066a4a9 --- /dev/null +++ b/src/util/param.c @@ -0,0 +1,134 @@ +#ifdef _MSC_VER +#include +#endif + +#include "language.h" +#include "log.h" +#include "param.h" +#include "parser.h" +#include "umlaut.h" + +#include + +#include +#include + +const char *parameters[MAXPARAMS] = { + "LOCALE", + "ALLES", + "JEDEM", + "BAUERN", + "BURG", + "EINHEIT", + "PRIVAT", + "HINTEN", + "KOMMANDO", + "KRAEUTER", + "NICHT", + "NAECHSTER", + "PARTEI", + "ERESSEA", + "PERSONEN", + "REGION", + "SCHIFF", + "SILBER", + "STRASSEN", + "TEMP", + "FLIEHE", + "GEBAEUDE", + "GIB", /* HELFE GIB */ + "KAEMPFE", + "DURCHREISE", + "BEWACHE", + "ZAUBER", + "PAUSE", + "VORNE", + "AGGRESSIV", + "DEFENSIV", + "STUFE", + "HELFE", + "FREMDES", + "AURA", + "HINTER", + "VOR", + "ANZAHL", + "GEGENSTAENDE", + "TRAENKE", + "GRUPPE", + "PARTEITARNUNG", + "BAEUME", + "ALLIANZ", + "AUTO" +}; + +param_t findparam(const char *s, const struct locale * lang) +{ + param_t result = NOPARAM; + char buffer[64]; + char * str = s ? transliterate(buffer, sizeof(buffer) - sizeof(int), s) : 0; + + if (str && *str) { + int i; + void * match; + void **tokens = get_translations(lang, UT_PARAMS); + critbit_tree *cb = (critbit_tree *)*tokens; + if (!cb) { + log_warning("no parameters defined in locale %s", locale_name(lang)); + } + else if (cb_find_prefix(cb, str, strlen(str), &match, 1, 0)) { + cb_get_kv(match, &i, sizeof(int)); + result = (param_t)i; + } + } + return result; +} + +param_t findparam_block(const char *s, const struct locale *lang, bool any_locale) +{ + param_t p; + if (!s || s[0] == '@') { + return NOPARAM; + } + p = findparam(s, lang); + if (any_locale && p == NOPARAM) { + const struct locale *loc; + for (loc = locales; loc; loc = nextlocale(loc)) { + if (loc != lang) { + p = findparam(s, loc); + if (p == P_FACTION || p == P_GAMENAME) { + break; + } + } + } + } + return p; +} + +bool isparam(const char *s, const struct locale * lang, param_t param) +{ + assert(s); + assert(param != P_GEBAEUDE); + assert(param != P_BUILDING); + if (s[0] > '@') { + param_t p = findparam(s, lang); + return p == param; + } + return false; +} + +param_t getparam(const struct locale * lang) +{ + char token[64]; + const char *s = gettoken(token, sizeof(token)); + return s ? findparam(s, lang) : NOPARAM; +} + +static const char * parameter_key(int i) +{ + assert(i < MAXPARAMS && i >= 0); + return parameters[i]; +} + +void init_parameters(struct locale *lang) { + init_translations(lang, UT_PARAMS, parameter_key, MAXPARAMS); +} diff --git a/src/util/param.h b/src/util/param.h new file mode 100644 index 000000000..42d34ee57 --- /dev/null +++ b/src/util/param.h @@ -0,0 +1,77 @@ +#pragma once + +#ifndef H_PARAM_H +#define H_PARAM_H + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + struct locale; + + typedef enum param_t { + P_LOCALE, + P_ANY, + P_EACH, + P_PEASANT, + P_BUILDING, + P_UNIT, + P_PRIVAT, + P_BEHIND, + P_CONTROL, + P_HERBS, + P_NOT, + P_NEXT, + P_FACTION, + P_GAMENAME, + P_PERSON, + P_REGION, + P_SHIP, + P_MONEY, + P_ROAD, + P_TEMP, + P_FLEE, + P_GEBAEUDE, + P_GIVE, + P_FIGHT, + P_TRAVEL, + P_GUARD, + P_ZAUBER, + P_PAUSE, + P_VORNE, + P_AGGRO, + P_CHICKEN, + P_LEVEL, + P_HELP, + P_FOREIGN, + P_AURA, + P_AFTER, + P_BEFORE, + P_NUMBER, + P_ITEMS, + P_POTIONS, + P_GROUP, + P_FACTIONSTEALTH, + P_TREES, + P_ALLIANCE, + P_AUTO, + MAXPARAMS, + NOPARAM + } param_t; + + extern const char *parameters[MAXPARAMS]; + + param_t findparam(const char *s, const struct locale *lang); + param_t findparam_block(const char *s, const struct locale *lang, bool any_locale); + bool isparam(const char *s, const struct locale * lang, param_t param); + param_t getparam(const struct locale *lang); + + void init_parameters(struct locale *lang); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/parser.c b/src/util/parser.c index 1ba913c2c..edcb5e3d6 100644 --- a/src/util/parser.c +++ b/src/util/parser.c @@ -1,4 +1,6 @@ +#ifdef _MSC_VER #include +#endif #include "parser.h" #include "unicode.h" #include "base36.h" diff --git a/src/util/parser.h b/src/util/parser.h index 7242da1bb..a540aa2ac 100644 --- a/src/util/parser.h +++ b/src/util/parser.h @@ -33,9 +33,6 @@ extern "C" { int getid(void); unsigned int atoip(const char *s); -#define getshipid() getid() -#define getfactionid() getid() - #ifdef __cplusplus } #endif diff --git a/src/util/password.c b/src/util/password.c index ac482d1f4..61ae8f2a0 100644 --- a/src/util/password.c +++ b/src/util/password.c @@ -1,18 +1,41 @@ +#ifdef _MSC_VER #include +#endif #include "password.h" +#include "crypto/crypto.h" + #include #include #include -bool password_is_implemented(int algo) { +int bcrypt_workfactor = 8; + +bool password_is_implemented(cryptalgo_t algo) { + if (algo == PASSWORD_BCRYPT) return true; return algo == PASSWORD_PLAINTEXT; } -const char * password_encode(const char * passwd, int algo) { +const char * password_hash(const char * passwd, cryptalgo_t algo) { + if (algo == PASSWORD_BCRYPT) { + char salt[BCRYPT_HASHSIZE]; + static char hash[BCRYPT_HASHSIZE]; + int ret; + bcrypt_gensalt(bcrypt_workfactor, salt); + ret = bcrypt_hashpw(passwd, salt, hash); + assert(ret == 0); + return hash; + } return passwd; } int password_verify(const char * pwhash, const char * passwd) { + if (pwhash[0] == '$') { + if (pwhash[1] == '2') { + int ret = bcrypt_checkpw(passwd, pwhash); + assert(ret != -1); + return (ret == 0) ? VERIFY_OK : VERIFY_FAIL; + } + } return (strcmp(passwd, pwhash) == 0) ? VERIFY_OK : VERIFY_FAIL; } diff --git a/src/util/password.h b/src/util/password.h index ba55f6cb9..7309e0c0e 100644 --- a/src/util/password.h +++ b/src/util/password.h @@ -1,12 +1,17 @@ #pragma once #include -#define PASSWORD_PLAINTEXT 0 -#define PASSWORD_DEFAULT PASSWORD_PLAINTEXT +typedef enum cryptalgo_t { + PASSWORD_PLAINTEXT, + PASSWORD_BCRYPT +} cryptalgo_t; +#define PASSWORD_DEFAULT PASSWORD_BCRYPT + +extern int bcrypt_workfactor; #define VERIFY_OK 0 #define VERIFY_FAIL 1 #define VERIFY_UNKNOWN 2 int password_verify(const char *hash, const char *passwd); -const char * password_encode(const char *passwd, int algo); -bool password_is_implemented(int algo); +const char * password_hash(const char *passwd, cryptalgo_t algo); +bool password_is_implemented(cryptalgo_t algo); diff --git a/src/util/password.test.c b/src/util/password.test.c index 8efe5b107..7ce2d0682 100644 --- a/src/util/password.test.c +++ b/src/util/password.test.c @@ -4,17 +4,29 @@ #include static void test_passwords(CuTest *tc) { - const char *hash, *expect; + const char *hash; - expect = "password"; - if (password_is_implemented(PASSWORD_PLAINTEXT)) { - hash = password_encode("password", PASSWORD_PLAINTEXT); + if (password_is_implemented(PASSWORD_BCRYPT)) { + int wf = bcrypt_workfactor; + bcrypt_workfactor = 4; + hash = password_hash("password", PASSWORD_BCRYPT); CuAssertPtrNotNull(tc, hash); - CuAssertStrEquals(tc, hash, expect); - CuAssertIntEquals(tc, VERIFY_OK, password_verify(expect, "password")); - CuAssertIntEquals(tc, VERIFY_FAIL, password_verify(expect, "arseword")); - } else { - CuAssertIntEquals(tc, VERIFY_UNKNOWN, password_verify(expect, "password")); + CuAssertIntEquals(tc, '$', hash[0]); + CuAssertIntEquals(tc, '2', hash[1]); + CuAssertIntEquals(tc, '$', hash[3]); + CuAssertIntEquals(tc, '0', hash[4]); + CuAssertIntEquals(tc, '4', hash[5]); + CuAssertIntEquals(tc, '$', hash[6]); + CuAssertIntEquals(tc, VERIFY_OK, password_verify(hash, "password")); + CuAssertIntEquals(tc, VERIFY_FAIL, password_verify(hash, "arseword")); + bcrypt_workfactor = wf; + } + if (password_is_implemented(PASSWORD_PLAINTEXT)) { + hash = password_hash("password", PASSWORD_PLAINTEXT); + CuAssertPtrNotNull(tc, hash); + CuAssertStrEquals(tc, hash, "password"); + CuAssertIntEquals(tc, VERIFY_OK, password_verify(hash, "password")); + CuAssertIntEquals(tc, VERIFY_FAIL, password_verify(hash, "arseword")); } } diff --git a/src/util/path.h b/src/util/path.h index 5a4e22270..649777171 100644 --- a/src/util/path.h +++ b/src/util/path.h @@ -1,4 +1,10 @@ +#pragma once #include +#ifdef _MSC_VER +/* @see https://insanecoding.blogspot.no/2007/11/pathmax-simply-isnt.html */ +#define PATH_MAX 260 +#endif + char * path_join(const char *p1, const char *p2, char *dst, size_t len); diff --git a/src/util/strings.c b/src/util/strings.c index ef351ab1f..4eac7856e 100644 --- a/src/util/strings.c +++ b/src/util/strings.c @@ -18,14 +18,15 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #ifdef _MSC_VER #include +#define HAVE__ITOA #endif #include "strings.h" /* libc includes */ +#include #include #include #include -#include #include #ifdef HAVE_LIBBSD @@ -34,6 +35,30 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #endif +const char* str_itoab(int val, int base) +{ + static char buf[32] = { 0 }; +#ifdef HAVE__ITOAB + return _itoa(val, buf, base); +#else + int i = 30; + for (; val && i; --i, val /= base) { + buf[i] = "0123456789abcdefghijklmnopqrstuvwxyz"[val % base]; + } + return &buf[i + 1]; +#endif +} + +const char *str_itoa(int n) +{ +#ifdef HAVE__ITOA + static char buf[32] = { 0 }; + return _itoa(n, buf, 10); +#else + return str_itoab(n, 10); +#endif +} + size_t str_strlcpy(char *dst, const char *src, size_t len) { #ifdef HAVE_BSDSTRING diff --git a/src/util/strings.h b/src/util/strings.h index bd6f0de58..bf6299332 100644 --- a/src/util/strings.h +++ b/src/util/strings.h @@ -20,6 +20,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #define STRINGS_H #include +#include #ifdef __cplusplus extern "C" { @@ -27,6 +28,8 @@ extern "C" { void str_replace(char *buffer, size_t size, const char *tmpl, const char *var, const char *value); int str_hash(const char *s); + const char *str_itoa(int i); + const char *str_itoab(int i, int base); size_t str_slprintf(char * dst, size_t size, const char * format, ...); size_t str_strlcpy(char *dst, const char *src, size_t len); size_t str_strlcat(char *dst, const char *src, size_t len); diff --git a/src/util/umlaut.c b/src/util/umlaut.c index 1f9e32b1f..00252fb02 100644 --- a/src/util/umlaut.c +++ b/src/util/umlaut.c @@ -117,7 +117,7 @@ char * transliterate(char * out, size_t size, const char * in) } tnode * mknode(void) { - tnode * node = calloc(1, sizeof(tnode)); + tnode * node = (tnode *)calloc(1, sizeof(tnode)); node->refcount = 1; return node; } diff --git a/src/volcano.c b/src/volcano.c index 7bddd6097..d4d045045 100644 --- a/src/volcano.c +++ b/src/volcano.c @@ -36,7 +36,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include /* util includes */ -#include +#include #include #include #include diff --git a/src/volcano.test.c b/src/volcano.test.c index c62febc0d..3ca670c7c 100644 --- a/src/volcano.test.c +++ b/src/volcano.test.c @@ -8,7 +8,7 @@ #include #include -#include +#include #include diff --git a/src/vortex.c b/src/vortex.c index 69d767c1b..c743ad857 100644 --- a/src/vortex.c +++ b/src/vortex.c @@ -4,8 +4,8 @@ #include #include -#include -#include +#include +#include #include #include #include @@ -51,6 +51,7 @@ void register_special_direction(struct locale *lang, const char *name) if (lang == locales) { dir_lookup *dl = malloc(sizeof(dir_lookup)); + assert(dl); dl->name = str; dl->oldname = token; dl->next = dir_name_lookup; diff --git a/src/wormhole.c b/src/wormhole.c index 197fc346d..1ce6686c9 100644 --- a/src/wormhole.c +++ b/src/wormhole.c @@ -12,7 +12,6 @@ #include #include -#include "settings.h" #include "wormhole.h" @@ -25,8 +24,8 @@ #include /* util includes */ -#include -#include +#include +#include #include #include #include @@ -104,7 +103,7 @@ static int wormhole_read(variant *var, void *owner, struct gamedata *data) if (data->version < ATTRIBOWNER_VERSION) { READ_INT(data->store, NULL); } - id = read_region_reference(data, (region **)&var->v, NULL); + id = read_region_reference(data, (region **)&var->v); return (id <= 0) ? AT_READ_FAIL : AT_READ_OK; } diff --git a/src/wormhole.test.c b/src/wormhole.test.c index b8baaa79a..bec4a5ff8 100644 --- a/src/wormhole.test.c +++ b/src/wormhole.test.c @@ -8,7 +8,7 @@ #include #include -#include +#include #include #include