forked from github/server
Merge branch 'master' of github.com:ennorehling/eressea
This commit is contained in:
commit
1eceef540a
136 changed files with 2800 additions and 1681 deletions
clibs
conf
process
res
core
translations
s
scripts
src
.DS_StoreCMakeLists.txtacademy.cacademy.halchemy.test.c
attributes
automate.cautomate.hautomate.test.cbattle.cbattle.hbattle.test.cbind_region.cbind_unit.cchaos.cchaos.hcreport.ceconomy.ceconomy.heconomy.test.ceressea.cexparse.cgive.test.cgmtool.cgmtool.hitems
kernel
build.cbuild.test.cbuilding.cconfig.cconfig.test.ccurse.test.cfaction.cfaction.test.citem.cmessages.cmessages.test.corder.corder.test.cregion.cregion.hresources.cresources.hsave.cship.hspell.test.ctypes.hunit.cunit.hversion.c
keyword.ckeyword.hlaws.claws.hlaws.test.clighthouse.clighthouse.hlighthouse.test.cmagic.cmain.cmonsters.cmove.cmove.hmove.test.cpiracy.test.crandenc.crenumber.test.c
2
clibs
2
clibs
|
@ -1 +1 @@
|
|||
Subproject commit f9842e07a442c5453c270badf25ab72633b4edf5
|
||||
Subproject commit ed5c4fee3afbc3d8be79d64857f30702aed522f8
|
|
@ -39,7 +39,7 @@
|
|||
"entertain.perlevel": 20,
|
||||
"taxing.perlevel": 20,
|
||||
"nmr.timeout": 5,
|
||||
"nmr.removenewbie": 0,
|
||||
"nmr.removenewbie": false,
|
||||
"GiveRestriction": 3,
|
||||
"hunger.long": true,
|
||||
"init_spells": 0,
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
{
|
||||
"include": [
|
||||
"config://res/translations/strings.de.po",
|
||||
"config://res/translations/strings-e2.de.po",
|
||||
"config://res/translations/strings.en.po",
|
||||
"config://res/translations/strings-e2.en.po",
|
||||
"config://res/translations/messages.de.po",
|
||||
"config://res/translations/messages.en.po",
|
||||
"config://res/core/messages.xml"
|
||||
|
|
|
@ -58,7 +58,7 @@
|
|||
"entertain.base": 0,
|
||||
"entertain.perlevel": 20,
|
||||
"nmr.timeout": 5,
|
||||
"nmr.removenewbie": 0,
|
||||
"nmr.removenewbie": false,
|
||||
"GiveRestriction": 3,
|
||||
"healing.forest": 2.0,
|
||||
"hunger.long": false,
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
SCRIPTS=compress.sh send-bz2-report send-zip-report create-orders \
|
||||
run-turn sendreports.sh
|
||||
IGNORE=sendreport.sh
|
||||
run-turn sendreports.sh sendreport.sh
|
||||
|
||||
shellcheck: $(SCRIPTS)
|
||||
shellcheck $(SCRIPTS)
|
||||
|
|
|
@ -28,7 +28,10 @@ if [ -e orders.$TURN ]; then
|
|||
files="$files orders.$TURN"
|
||||
fi
|
||||
echo "backup turn $TURN, game $GAME, files: $files"
|
||||
if [ -d reports ] ; then
|
||||
tar cjf backup/$TURN-reports.tar.bz2 reports
|
||||
fi
|
||||
tar cjf backup/$TURN.tar.bz2 $files
|
||||
echo "uploading game-$GAME/$TURN.tar.bz2"
|
||||
curl -s -n -T backup/$TURN.tar.bz2 https://dav.box.com/dav/Eressea/game-$GAME/$TURN.tar.bz2
|
||||
curl -s -n -T eressea.db https://dav.box.com/dav/Eressea/eressea.db
|
||||
#curl -s -n -T eressea.db https://dav.box.com/dav/Eressea/eressea.db
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#!/bin/bash
|
||||
|
||||
(
|
||||
[ "$PREVIEW" != "yes" ] && exit
|
||||
[ -z ${ERESSEA} ] && ERESSEA=$HOME/eressea
|
||||
|
||||
|
@ -13,3 +13,5 @@ for game in 2 3 4 ; do
|
|||
${SRC}/s/preview -g ${game} run && \
|
||||
${SRC}/s/preview -g ${game} send
|
||||
done
|
||||
) | tee -a $HOME/log/preview.cron.log
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/bin/bash
|
||||
GAME=$1
|
||||
|
||||
(
|
||||
[ "$ENABLED" != "yes" ] && exit
|
||||
[ -z ${ERESSEA} ] && ERESSEA=$HOME/eressea
|
||||
|
||||
|
@ -58,3 +58,5 @@ $BIN/compress.sh $GAME $TURN
|
|||
$BIN/sendreports.sh $GAME
|
||||
$BIN/backup-eressea $GAME $TURN
|
||||
rm -f test/execute.lock
|
||||
) | tee -a $HOME/log/eressea.cron.log
|
||||
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
PATH=$ERESSEA/bin:$PATH
|
||||
|
||||
function abort() {
|
||||
if [ $# -gt 0 ]; then
|
||||
echo $@
|
||||
fi
|
||||
exit -1
|
||||
}
|
|
@ -25,6 +25,6 @@ addr=$1
|
|||
subj=$2
|
||||
shift 2
|
||||
|
||||
mutt -F "$ERESSEA/etc/muttrc" -s "$subj" -a "$@" -- "$addr" \
|
||||
mutt -s "$subj" -a "$@" -- "$addr" \
|
||||
< "$ERESSEA/server/etc/$TEMPLATE"
|
||||
|
||||
|
|
|
@ -44,6 +44,6 @@ addr=$1
|
|||
subject=$2
|
||||
shift 2
|
||||
|
||||
mutt -F "$ERESSEA/etc/muttrc" -s "$subject" -a "$@" -- "$addr" \
|
||||
mutt -s "$subject" -a "$@" -- "$addr" \
|
||||
< "$TEMPLATE" || echo "Sending failed for email/report: $2/$3"
|
||||
|
||||
|
|
|
@ -1,11 +1,17 @@
|
|||
#!/bin/bash
|
||||
|
||||
|
||||
if [ -z $ERESSEA ]; then
|
||||
if [ -z "$ERESSEA" ]; then
|
||||
echo "You have to define the \$ERESSEA environment variable to run $0"
|
||||
exit -2
|
||||
fi
|
||||
source $HOME/bin/functions.sh
|
||||
|
||||
function abort() {
|
||||
if [ $# -gt 0 ]; then
|
||||
echo "$@"
|
||||
fi
|
||||
exit -1
|
||||
}
|
||||
|
||||
GAME=$1
|
||||
EMAIL=$2
|
||||
|
@ -14,32 +20,33 @@ PASSWD=$4
|
|||
#echo "$GAME $EMAIL $FACTION $PASSWD" >> /tmp/report.log
|
||||
|
||||
function reply() {
|
||||
echo $@ | mutt -s "Reportnachforderung Partei ${FACTION}" $EMAIL
|
||||
abort $@
|
||||
echo "$@" | mutt -s "Reportnachforderung Partei ${FACTION}" "$EMAIL"
|
||||
abort "$@"
|
||||
}
|
||||
|
||||
LOCKFILE=$ERESSEA/.report.lock
|
||||
[ -e $LOCKFILE ] && reply "lockfile exists. wait for mail delivery to finish."
|
||||
LOCKFILE="$ERESSEA/.report.lock"
|
||||
[ -e "$LOCKFILE" ] && reply "lockfile exists. wait for mail delivery to finish."
|
||||
|
||||
REPLYTO='accounts@eressea.de'
|
||||
echo "$(date):report:$GAME:$EMAIL:$FACTION:$PASSWD" >> "$ERESSEA/request.log"
|
||||
|
||||
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"
|
||||
|
||||
cd $ERESSEA
|
||||
checkpasswd.py game-$GAME/passwd $FACTION $PASSWD || reply "Das Passwort fuer die Partei $FACTION ist ungueltig"
|
||||
|
||||
cd $ERESSEA/game-$GAME/reports
|
||||
if [ ! -e ${FACTION}.sh ]; then
|
||||
cd "$ERESSEA/game-$GAME/reports" || exit
|
||||
if [ ! -e "${FACTION}.sh" ]; then
|
||||
echo "Der Report für Partei $FACTION kann wegen technischer Probleme leider nicht nachgefordert werden: No such file ${FACTION}.sh" \
|
||||
| mutt -s "Reportnachforderung Partei ${FACTION}" $EMAIL
|
||||
| mutt -s "Reportnachforderung Partei ${FACTION}" "$EMAIL"
|
||||
exit
|
||||
fi
|
||||
|
||||
source ${FACTION}.sh $EMAIL || reply "Unbekannte Partei $FACTION"
|
||||
bash "${FACTION}.sh" "$EMAIL" || reply "Unbekannte Partei $FACTION"
|
||||
|
||||
if [ -e $ERESSEA/game-$GAME/eressea.db ]; then
|
||||
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")
|
||||
echo "Der Report Deiner Partei wurde an ${EMAIL} gesandt." \
|
||||
| mutt -s "Reportnachforderung Partei ${FACTION}" $OWNER
|
||||
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
|
||||
fi
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
</type>
|
||||
</message>
|
||||
|
||||
<message name="target_region_invalid">
|
||||
<message name="target_region_invalid" section="errors">
|
||||
<type>
|
||||
<arg name="unit" type="unit"/>
|
||||
<arg name="region" type="region"/>
|
||||
|
@ -38,7 +38,7 @@
|
|||
</type>
|
||||
</message>
|
||||
|
||||
<message name="missing_direction">
|
||||
<message name="missing_direction" section="errors">
|
||||
<type>
|
||||
<arg name="unit" type="unit"/>
|
||||
<arg name="region" type="region"/>
|
||||
|
@ -46,7 +46,7 @@
|
|||
</type>
|
||||
</message>
|
||||
|
||||
<message name="target_region_not_empty">
|
||||
<message name="target_region_not_empty" section="errors">
|
||||
<type>
|
||||
<arg name="unit" type="unit"/>
|
||||
<arg name="region" type="region"/>
|
||||
|
@ -868,21 +868,6 @@
|
|||
</type>
|
||||
</message>
|
||||
|
||||
<message name="sink_lost_msg" section="events">
|
||||
<type>
|
||||
<arg name="dead" type="int"/>
|
||||
<arg name="region" type="region"/>
|
||||
<arg name="unit" type="unit"/>
|
||||
</type>
|
||||
</message>
|
||||
|
||||
<message name="sink_saved_msg" section="events">
|
||||
<type>
|
||||
<arg name="region" type="region"/>
|
||||
<arg name="unit" type="unit"/>
|
||||
</type>
|
||||
</message>
|
||||
|
||||
<message name="sink_msg" section="events">
|
||||
<type>
|
||||
<arg name="ship" type="ship"/>
|
||||
|
|
|
@ -1773,7 +1773,7 @@ msgid "storm"
|
|||
msgstr "\"Die $ship($ship) wird in $region($region) von Stürmen abgetrieben$if($sink,\" und sinkt\",\"\").\""
|
||||
|
||||
msgid "nr_insectwinter"
|
||||
msgstr "Es ist Winter, und Insekten können nur in Wüsten oder mit Hilfe des Nestwärme-Tranks Personen rekrutieren."
|
||||
msgstr "Insekten können wegen des Winterwetters in der kommenden Woche nur in Wüsten oder mit Hilfe des Nestwärme-Tranks Personen rekrutieren."
|
||||
|
||||
msgid "spellfail_nomonsters"
|
||||
msgstr "\"$unit($unit) in $region($region): '$order($command)' - Dieser Zauber kann nicht auf Monster gezaubert werden.\""
|
||||
|
@ -2121,7 +2121,7 @@ msgid "missing_components"
|
|||
msgstr "\"$unit($unit) hat nicht genügend Komponenten um $spell($spell) auf Stufe $int($level) zu zaubern.\""
|
||||
|
||||
msgid "seduce_effect_1"
|
||||
msgstr "\"$unit($unit) verfiel dem Glücksspiel und hat fast sein ganzes Hab und gut verspielt.\""
|
||||
msgstr "\"$unit($unit) verfiel dem Glücksspiel und hat fast sein ganzes Hab und Gut verspielt.\""
|
||||
|
||||
msgid "xmastree_effect"
|
||||
msgstr "\"In der Region erstrahlen des Nachts bunte Lichter, Gloeckchen klingeln und frohes Kindergelaechter klingt durch den Wald.\""
|
||||
|
@ -2303,9 +2303,6 @@ msgstr "\"$unit($mage) erleidet durch den Tod seines Vertrauten einen Schock.\""
|
|||
msgid "error269"
|
||||
msgstr "\"$unit($unit) in $region($region): '$order($command)' - Hier kann man nicht zaubern.\""
|
||||
|
||||
msgid "sink_saved_msg"
|
||||
msgstr "\"$unit($unit) überlebt unbeschadet und rettet sich nach $region($region).\""
|
||||
|
||||
msgid "race_noregroup"
|
||||
msgstr "\"$unit($unit) in $region($region): '$order($command)' - $race($race,0) können nicht neu gruppiert werden.\""
|
||||
|
||||
|
@ -2654,9 +2651,6 @@ msgstr "\"$unit($unit) in $region($region): '$order($command)' - Die Einheit kan
|
|||
msgid "analyse_building_noage"
|
||||
msgstr "\"$unit($mage) fand heraus, dass auf $building($building) der Zauber '$curse($curse)' liegt, dessen Kraft ausreicht, um noch Jahrhunderte bestehen zu bleiben.\""
|
||||
|
||||
msgid "sink_lost_msg"
|
||||
msgstr "\"$int($amount) Personen von $unit($unit) ertrinken.$if($isnull($region),\"\",\" Die Einheit rettet sich nach $region($region).\")\""
|
||||
|
||||
msgid "error130"
|
||||
msgstr "\"$unit($unit) in $region($region): '$order($command)' - Syntax: MAGIEGEBIET [1-5].\""
|
||||
|
||||
|
@ -2733,7 +2727,7 @@ msgid "volcanostartsmoke"
|
|||
msgstr "\"Aus dem Vulkankrater von $region($region) steigt plötzlich Rauch.\""
|
||||
|
||||
msgid "nr_insectfall"
|
||||
msgstr "Es ist Spätherbst, und diese Woche ist die letzte vor dem Winter, in der Insekten rekrutieren können."
|
||||
msgstr "Es ist Spätherbst, und die kommende Woche ist die letzte vor dem Winter, in der Insekten rekrutieren können."
|
||||
|
||||
msgid "error296"
|
||||
msgstr "\"$unit($unit) in $region($region): '$order($command)' - Hier werden niemals Bäume wachsen.\""
|
||||
|
|
|
@ -2303,9 +2303,6 @@ msgstr "\"$unit($mage) receives a shock when his familiar dies.\""
|
|||
msgid "error269"
|
||||
msgstr "\"$unit($unit) in $region($region): '$order($command)' - You cannot cast spells here.\""
|
||||
|
||||
msgid "sink_saved_msg"
|
||||
msgstr "\"$unit($unit) survives unscathed and makes it to $region($region).\""
|
||||
|
||||
msgid "race_noregroup"
|
||||
msgstr "\"$unit($unit) in $region($region): '$order($command)' - $race($race,0) cannot be regrouped.\""
|
||||
|
||||
|
@ -2654,9 +2651,6 @@ msgstr "\"$unit($unit) in $region($region): '$order($command)' - The unit cannot
|
|||
msgid "analyse_building_noage"
|
||||
msgstr "\"$unit($mage) discovers that $building($building) is charmed with '$curse($curse)', which will last for centuries.\""
|
||||
|
||||
msgid "sink_lost_msg"
|
||||
msgstr "\"$int($amount) people of $unit($unit) drown.$if($isnull($region),\"\",\" The unit makes it to $region($region).\")\""
|
||||
|
||||
msgid "error130"
|
||||
msgstr "\"$unit($unit) in $region($region): '$order($command)' - Syntax: MAGIC SPHERE [1-5].\""
|
||||
|
||||
|
|
49
res/translations/strings-e2.de.po
Normal file
49
res/translations/strings-e2.de.po
Normal file
|
@ -0,0 +1,49 @@
|
|||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"POT-Creation-Date: \n"
|
||||
"PO-Revision-Date: \n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: de\n"
|
||||
"X-Generator: Poedit 2.0.7\n"
|
||||
|
||||
msgctxt "spellinfo"
|
||||
msgid "concealing_aura"
|
||||
msgstr "Dieser Zauber wird die gesamte Ausrüstung der Zieleinheit für einige Zeit vor den Blicken anderer verschleiern."
|
||||
|
||||
msgctxt "spellinfo"
|
||||
msgid "raindance"
|
||||
msgstr "Dieses uralte Tanzritual ruft die Kräfte des Lebens und der Fruchtbarkeit. Die Erträge der Bauern werden für einige Wochen deutlich besser ausfallen."
|
||||
|
||||
msgctxt "spellinfo"
|
||||
msgid "earn_silver#gwyrrd"
|
||||
msgstr "Die Fähigkeiten der Gwyrrd-Magier in der Viehzucht und Heilung sind bei den Bauern sehr begehrt. Gerade auf Märkten sind ihre Dienste häufig sehr gefragt. Manch einer mag auch sein Talent dazu nutzen, ein Tier für einen besseren Preis zu verkaufen. Pro Stufe kann der Magier so 50 Silber verdienen."
|
||||
|
||||
msgctxt "spellinfo"
|
||||
msgid "earn_silver#draig"
|
||||
msgstr "In den dunkleren Gassen gibt es sie, die Flüche und Verhexungen auf Bestellung. Aber auch Gegenzauber hat der Jünger des Draigs natürlich im Angebot. Ob nun der Sohn des Nachbarn in einen Liebesbann gezogen werden soll oder die Nebenbuhlerin Pickel und Warzen bekommen soll, niemand gibt gerne zu, zu solchen Mitteln gegriffen zu haben. Für diese Dienstleistung streicht der Magier 50 Silber pro Stufe ein."
|
||||
|
||||
msgctxt "spellinfo"
|
||||
msgid "earn_silver#cerddor"
|
||||
msgstr "Cerddormagier sind die führenden Gaukler unter den Magiern, sie lieben es das Volk zu unterhalten und im Mittelpunkt zu stehen. Schon Anfänger lernen die kleinen Kunststücke und magischen Tricks, mit denen man das Volk locken und verführen kann, den Geldbeutel ganz weit zu öffnen, und am Ende der Woche wird der Gaukler 50 Silber pro Stufe verdient haben."
|
||||
|
||||
msgctxt "spellinfo"
|
||||
msgid "earn_silver#tybied"
|
||||
msgstr "Wenn einem der Alchemist nicht weiterhelfen kann, geht man zu dem gelehrten Tybiedmagier. Seine Tränke und Tinkturen helfen gegen alles, was man sonst nicht bekommen kann. Ob nun die kryptische Formel unter dem Holzschuh des untreuen Ehemannes wirklich geholfen hat - nun, der des Lesens nicht mächtige Bauer wird es nie wissen. Dem Magier hilft es auf jeden Fall... beim Füllen seines Geldbeutels. 50 Silber pro Stufe lassen sich so in einer Woche verdienen."
|
||||
|
||||
msgctxt "spellinfo"
|
||||
msgid "earn_silver#illaun"
|
||||
msgstr "Niemand kann so gut die Träume deuten wie ein Magier des Illaun. Auch die Kunst der Wahrsagerei, des Kartenlegens und des Handlesens sind ihm geläufig. Dafür zahlen ihm die Bauern 50 Silber pro Stufe."
|
||||
|
||||
msgctxt "describe"
|
||||
msgid "lifepotion"
|
||||
msgstr "Das 'Wasser des Lebens' ist in der Lage, aus gefällten Baumstämmen wieder lebende Bäume zu machen. Dazu wird ein knotiger Saugwurz zusammen mit einem Elfenlieb erwärmt, so dass man gerade noch den Finger reinhalten kann. Dies gieße man in ein Gefäß und lasse es langsam abkühlen. Der Extrakt reicht für 10 Holzstämme."
|
||||
|
||||
msgctxt "spellinfo"
|
||||
msgid "blessedharvest"
|
||||
msgstr "Dieses Ernteritual verbessert die Erträge der arbeitenden Bauern in der Region um ein Silberstück. Je mehr Kraft der Druide investiert, desto länger wirkt der Zauber."
|
||||
|
49
res/translations/strings-e2.en.po
Normal file
49
res/translations/strings-e2.en.po
Normal file
|
@ -0,0 +1,49 @@
|
|||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"POT-Creation-Date: \n"
|
||||
"PO-Revision-Date: \n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: en\n"
|
||||
"X-Generator: Poedit 2.0.7\n"
|
||||
|
||||
msgctxt "spellinfo"
|
||||
msgid "earn_silver#gwyrrd"
|
||||
msgstr "The abilities of the mages of Gwyrrd concerning the breeding and healing of cattle are highly appreciated among the peasants. Especially at the markets, their services are demanded frequently. Some of them also use their talents to sell an animal at a higher price. A magician can earn 50 silver pieces per level in this way."
|
||||
|
||||
msgctxt "spellinfo"
|
||||
msgid "earn_silver#draig"
|
||||
msgstr "In the dark alleys you can find those who sell curses and hexes on demand - but you can buy the apropriate counterspells from the followers of Draig as well. May it be a love spell for the son of a neighbour or a wart in the face of a rival. For offering these services, the sorcerer charges 50 silver pieces per level."
|
||||
|
||||
msgctxt "spellinfo"
|
||||
msgid "earn_silver#cerddor"
|
||||
msgstr "The mages of Cerddor truly are the bards of the wizards; they love to use their sorcery to entertain the crowds and to be the center of attention. Even the apprentices study those little magic tricks, which attract and fascinate the people and thus ensnare them into leaving a few coins or more for the artist. By the end of the week, the bard will have earned 50 silver per level."
|
||||
|
||||
msgctxt "spellinfo"
|
||||
msgid "earn_silver#illaun"
|
||||
msgstr "No one can read dreams as well as the mages of Illaun. Furthermore, they are also familiar with all other common means of foretelling the future like crystal balls, tarot cards or palms. A mentalist can earn 50 silver pieces per level and week for offering these services to peasants."
|
||||
|
||||
msgctxt "spellinfo"
|
||||
msgid "earn_silver#tybied"
|
||||
msgstr "If the local alchemist could not help you, you should visit a scholar of Tybied. His potions and tinctures may help when nothing else does. If the cryptic formula under the wooden shoes of the unfaithful husband really helped? - well, the peasant, who isn't capable of reading, will never know. At least it helped the magician... to fill his purse. In one week he can earn 50 silver per level that way."
|
||||
|
||||
msgctxt "spellinfo"
|
||||
msgid "blessedharvest"
|
||||
msgstr "This ritual increases the output of the local farms. Peasants in the region produce an extra silverpiece. The stronger the druid's spell is, the longer the effect will last."
|
||||
|
||||
msgctxt "spellinfo"
|
||||
msgid "raindance"
|
||||
msgstr "This ancient rite calls upon the forces of life and fertility. For the next few weeks, the peasant's harvest will be extraordinary good."
|
||||
|
||||
msgctxt "spellinfo"
|
||||
msgid "concealing_aura"
|
||||
msgstr "This spell will hide the whole equipment of a target unit from the looks of others."
|
||||
|
||||
msgctxt "describe"
|
||||
msgid "lifepotion"
|
||||
msgstr "The \"Water of Life\" allows living trees to be created from logs. A Knotroot and Elvendear are heated until one can just still keep one's finger in. This is then poured into a jar and allowed to cool slowly. The extract is sufficient for 10 pieces of wood."
|
||||
|
|
@ -327,10 +327,6 @@ msgctxt "spell"
|
|||
msgid "clone"
|
||||
msgstr "Seelenkopie"
|
||||
|
||||
msgctxt "spellinfo"
|
||||
msgid "concealing_aura"
|
||||
msgstr "Dieser Zauber wird die gesamte Ausrüstung der Zieleinheit für einige Zeit vor den Blicken anderer verschleiern."
|
||||
|
||||
msgctxt "shipinfo"
|
||||
msgid "balloon"
|
||||
msgstr "Der Sumpfgasballon besteht aus einem großen Weidenkorb, welcher Platz für maximal 5 Personen oder 500 Gewichtseinheiten bietet, und einer großen, mit Sumpfgas gefüllten Wyrmblase. Bei guten Winden kann sich der Ballon zwei Regionen pro Woche fortbewegen. Das Führen eines Ballons ist nicht einfach, und der Kapitän muss mindestens ein Segeltalent von 6 besitzen. Diese neue Entwicklung auf Eressea wird ausschließlich für den Xontormia-Expreß hergestellt und die Baupläne sind streng geheim. So ist es auch bisher noch niemandem gelungen, ein Exemplar nachzubauen."
|
||||
|
@ -908,10 +904,6 @@ msgctxt "spellinfo"
|
|||
msgid "disturbingdreams"
|
||||
msgstr "Dieser Zauber führt in der betroffenen Region für einige Wochen zu Schlaflosigkeit und Unruhe. Den Betroffenen fällt das Lernen deutlich schwerer."
|
||||
|
||||
msgctxt "spellinfo"
|
||||
msgid "raindance"
|
||||
msgstr "Dieses uralte Tanzritual ruft die Kräfte des Lebens und der Fruchtbarkeit. Die Erträge der Bauern werden für einige Wochen deutlich besser ausfallen."
|
||||
|
||||
msgid "wdw_pyramid"
|
||||
msgstr "Pyramide"
|
||||
|
||||
|
@ -1459,10 +1451,6 @@ msgctxt "race"
|
|||
msgid "goblin_x"
|
||||
msgstr "Goblin"
|
||||
|
||||
msgctxt "spellinfo"
|
||||
msgid "earn_silver#gwyrrd"
|
||||
msgstr "Die Fähigkeiten der Gwyrrd-Magier in der Viehzucht und Heilung sind bei den Bauern sehr begehrt. Gerade auf Märkten sind ihre Dienste häufig sehr gefragt. Manch einer mag auch sein Talent dazu nutzen, ein Tier für einen besseren Preis zu verkaufen. Pro Stufe kann der Magier so 50 Silber verdienen."
|
||||
|
||||
msgctxt "spell"
|
||||
msgid "raindance"
|
||||
msgstr "Regentanz"
|
||||
|
@ -1494,10 +1482,6 @@ msgstr "Mallorn"
|
|||
msgid "mallorn_p"
|
||||
msgstr "Mallorn"
|
||||
|
||||
msgctxt "describe"
|
||||
msgid "lifepotion"
|
||||
msgstr "Das 'Wasser des Lebens' ist in der Lage, aus gefällten Baumstämmen wieder lebende Bäume zu machen. Dazu wird ein knotiger Saugwurz zusammen mit einem Elfenlieb erwärmt, so dass man gerade noch den Finger reinhalten kann. Dies gieße man in ein Gefäß und lasse es langsam abkühlen. Der Extrakt reicht für 10 Holzstämme."
|
||||
|
||||
msgctxt "spell"
|
||||
msgid "homestone"
|
||||
msgstr "Heimstein"
|
||||
|
@ -1740,10 +1724,6 @@ msgstr "Beschwörung eines Wasserelementares"
|
|||
msgid "GEBAEUDE"
|
||||
msgstr "GEBÄUDE"
|
||||
|
||||
msgctxt "spellinfo"
|
||||
msgid "blessedharvest"
|
||||
msgstr "Dieses Ernteritual verbessert die Erträge der arbeitenden Bauern in der Region um ein Silberstück. Je mehr Kraft der Druide investiert, desto länger wirkt der Zauber."
|
||||
|
||||
msgid "KRAEUTER"
|
||||
msgstr "KRÄUTER"
|
||||
|
||||
|
@ -2884,6 +2864,9 @@ msgstr "der Schatten"
|
|||
msgid "ALLES"
|
||||
msgstr "ALLES"
|
||||
|
||||
msgid "AUTO"
|
||||
msgstr "AUTO"
|
||||
|
||||
msgid "undead_postfix_2"
|
||||
msgstr "der Finsternis"
|
||||
|
||||
|
@ -3147,10 +3130,6 @@ msgctxt "spellinfo"
|
|||
msgid "create_focus"
|
||||
msgstr "Erzeugt einen Aurafokus."
|
||||
|
||||
msgctxt "spellinfo"
|
||||
msgid "earn_silver#draig"
|
||||
msgstr "In den dunkleren Gassen gibt es sie, die Flüche und Verhexungen auf Bestellung. Aber auch Gegenzauber hat der Jünger des Draigs natürlich im Angebot. Ob nun der Sohn des Nachbarn in einen Liebesbann gezogen werden soll oder die Nebenbuhlerin Pickel und Warzen bekommen soll, niemand gibt gerne zu, zu solchen Mitteln gegriffen zu haben. Für diese Dienstleistung streicht der Magier 50 Silber pro Stufe ein."
|
||||
|
||||
msgctxt "spell"
|
||||
msgid "song_of_slavery"
|
||||
msgstr "Gesang der Versklavung"
|
||||
|
@ -4910,10 +4889,6 @@ msgstr "Elixier der Macht"
|
|||
msgid "wand_p"
|
||||
msgstr "Zauberstäbe"
|
||||
|
||||
msgctxt "spellinfo"
|
||||
msgid "earn_silver#cerddor"
|
||||
msgstr "Cerddormagier sind _die_ Gaukler unter den Magiern, sie lieben es das Volk zu unterhalten und im Mittelpunkt zu stehen. Schon Anfänger lernen die kleinen Kunststücke und magischen Tricks, mit denen man das Volk locken und verführen kann, den Geldbeutel ganz weit zu öffnen, und am Ende der Woche wird der Gaukler 50 Silber pro Stufe verdient haben."
|
||||
|
||||
msgctxt "spell"
|
||||
msgid "strength"
|
||||
msgstr "Unbekannter Effekt"
|
||||
|
@ -4996,10 +4971,6 @@ msgstr "Myrrhe"
|
|||
msgid "skeleton_prefix_9"
|
||||
msgstr "Dunkle"
|
||||
|
||||
msgctxt "spellinfo"
|
||||
msgid "earn_silver#illaun"
|
||||
msgstr "Niemand kann so gut die Träume deuten wie ein Magier des Illaun. Auch die Kunst der Wahrsagerei, des Kartenlegens und des Handlesens sind ihm geläufig. Dafür zahlen ihm die Bauern 50 Silber pro Stufe."
|
||||
|
||||
msgctxt "spell"
|
||||
msgid "big_recruit"
|
||||
msgstr "Hohe Kunst der Überzeugung"
|
||||
|
@ -5913,10 +5884,6 @@ msgctxt "spell"
|
|||
msgid "cerddorfumbleshield"
|
||||
msgstr "Bannlied"
|
||||
|
||||
msgctxt "spellinfo"
|
||||
msgid "earn_silver#tybied"
|
||||
msgstr "Wenn einem der Alchemist nicht weiterhelfen kann, geht man zu dem gelehrten Tybiedmagier. Seine Tränke und Tinkturen helfen gegen alles, was man sonst nicht bekommen kann. Ob nun die kryptische Formel unter dem Holzschuh des untreuen Ehemannes wirklich geholfen hat - nun, der des Lesens nicht mächtige Bauer wird es nie wissen. Dem Magier hilft es auf jeden Fall... beim Füllen seines Geldbeutels. 50 Silber pro Stufe lassen sich so in einer Woche verdienen."
|
||||
|
||||
msgid "ANZAHL"
|
||||
msgstr "ANZAHL"
|
||||
|
||||
|
@ -5994,6 +5961,10 @@ msgctxt "keyword"
|
|||
msgid "maketemp"
|
||||
msgstr "MACHE TEMP"
|
||||
|
||||
msgctxt "keyword"
|
||||
msgid "autostudy"
|
||||
msgstr "LERNE AUTO"
|
||||
|
||||
msgctxt "spell"
|
||||
msgid "reanimate"
|
||||
msgstr "Wiederbelebung"
|
||||
|
|
|
@ -273,10 +273,6 @@ msgctxt "spell"
|
|||
msgid "clone"
|
||||
msgstr "Doppelganger"
|
||||
|
||||
msgctxt "spellinfo"
|
||||
msgid "concealing_aura"
|
||||
msgstr "This spell will hide the whole equipment of a target unit from the looks of others."
|
||||
|
||||
msgctxt "spell"
|
||||
msgid "bloodsacrifice"
|
||||
msgstr "Lesser Sacrifice"
|
||||
|
@ -695,10 +691,6 @@ msgctxt "spellinfo"
|
|||
msgid "disturbingdreams"
|
||||
msgstr "This spell causes insomnia and restlessness in a whole region for several weeks. All affected persons will learn much slower than normal."
|
||||
|
||||
msgctxt "spellinfo"
|
||||
msgid "raindance"
|
||||
msgstr "This ancient rite calls upon the forces of life and fertility. For the next few weeks, the peasant's harvest will be extraordinary good."
|
||||
|
||||
msgid "wdw_pyramid"
|
||||
msgstr "pyramid"
|
||||
|
||||
|
@ -1221,10 +1213,6 @@ msgctxt "race"
|
|||
msgid "goblin_x"
|
||||
msgstr "goblin"
|
||||
|
||||
msgctxt "spellinfo"
|
||||
msgid "earn_silver#gwyrrd"
|
||||
msgstr "The abilities of the mages of Gwyrrd concerning the breeding and healing of cattle are highly appreciated among the peasants. Especially at the markets, their services are demanded frequently. Some of them also use their talents to sell an animal at a higher price. A magician can earn 50 silver pieces per level in this way."
|
||||
|
||||
msgctxt "spell"
|
||||
msgid "raindance"
|
||||
msgstr "Rain Dance"
|
||||
|
@ -1252,10 +1240,6 @@ msgstr "mallorn"
|
|||
msgid "mallorn_p"
|
||||
msgstr "mallorn"
|
||||
|
||||
msgctxt "describe"
|
||||
msgid "lifepotion"
|
||||
msgstr "The \"Water of Life\" allows living trees to be created from logs. A Knotroot and Elvendear are heated until one can just still keep one's finger in. This is then poured into a jar and allowed to cool slowly. The extract is sufficient for 10 pieces of wood."
|
||||
|
||||
msgid "thickfog_trail"
|
||||
msgstr "%s"
|
||||
|
||||
|
@ -1490,10 +1474,6 @@ msgctxt "spell"
|
|||
msgid "goodwinds"
|
||||
msgstr "Summon Water Elemental"
|
||||
|
||||
msgctxt "spellinfo"
|
||||
msgid "blessedharvest"
|
||||
msgstr "This ritual increases the output of the local farms. Peasants in the region produce an extra silverpiece. The stronger the druid's spell is, the longer the effect will last."
|
||||
|
||||
msgid "KRAEUTER"
|
||||
msgstr "HERBS"
|
||||
|
||||
|
@ -2530,6 +2510,9 @@ msgstr "halfling foot"
|
|||
msgid "ALLES"
|
||||
msgstr "ALL"
|
||||
|
||||
msgid "AUTO"
|
||||
msgstr "AUTO"
|
||||
|
||||
msgctxt "race"
|
||||
msgid "songdragon_d"
|
||||
msgstr "song dragons"
|
||||
|
@ -2732,10 +2715,6 @@ msgctxt "spellinfo"
|
|||
msgid "create_focus"
|
||||
msgstr "Creates an aurafocus crystal."
|
||||
|
||||
msgctxt "spellinfo"
|
||||
msgid "earn_silver#draig"
|
||||
msgstr "In the dark alleys you can find those who sell curses and hexes on demand - but you can buy the apropriate counterspells from the followers of Draig as well. May it be a love spell for the son of a neighbour or a wart in the face of a rival. For offering these services, the sorcerer charges 50 silver pieces per level."
|
||||
|
||||
msgctxt "spell"
|
||||
msgid "song_of_slavery"
|
||||
msgstr "Song of Slavery"
|
||||
|
@ -4370,10 +4349,6 @@ msgstr "elixir of power"
|
|||
msgid "wand_p"
|
||||
msgstr "wands"
|
||||
|
||||
msgctxt "spellinfo"
|
||||
msgid "earn_silver#cerddor"
|
||||
msgstr "The mages of Cerddor truly are the bards of the wizards; they love to use their sorcery to entertain the crowds and to be the center of attention. Even the apprentices study those little magic tricks, which attract and fascinate the people and thus ensnare them into leaving a few coins or more for the artist. By the end of the week, the bard will have earned 50 silver per level."
|
||||
|
||||
msgctxt "spell"
|
||||
msgid "strength"
|
||||
msgstr "Unknown Effect"
|
||||
|
@ -4426,10 +4401,6 @@ msgstr "trees"
|
|||
msgid "myrrh_p"
|
||||
msgstr "myrrh"
|
||||
|
||||
msgctxt "spellinfo"
|
||||
msgid "earn_silver#illaun"
|
||||
msgstr "No one can read dreams as well as the mages of Illaun. Furthermore, they are also familiar with all other common means of foretelling the future like crystal balls, tarot cards or palms. A mentalist can earn 50 silver pieces per level and week for offering these services to peasants."
|
||||
|
||||
msgctxt "spell"
|
||||
msgid "big_recruit"
|
||||
msgstr "High art of persuasion"
|
||||
|
@ -5222,10 +5193,6 @@ msgctxt "spell"
|
|||
msgid "cerddorfumbleshield"
|
||||
msgstr "Countersong"
|
||||
|
||||
msgctxt "spellinfo"
|
||||
msgid "earn_silver#tybied"
|
||||
msgstr "If the local alchemist could not help you, you should visit a scholar of Tybied. His potions and tinctures may help when nothing else does. If the cryptic formula under the wooden shoes of the unfaithful husband really helped? - well, the peasant, who isn't capable of reading, will never know. At least it helped the magician... to fill his purse. In one week he can earn 50 silver per level that way."
|
||||
|
||||
msgctxt "keyword"
|
||||
msgid "teach"
|
||||
msgstr "TEACH"
|
||||
|
@ -5304,7 +5271,11 @@ msgstr "berserkers blood potions"
|
|||
|
||||
msgctxt "keyword"
|
||||
msgid "maketemp"
|
||||
msgstr "MAKETEMP"
|
||||
msgstr "MAKE TEMP"
|
||||
|
||||
msgctxt "keyword"
|
||||
msgid "autostudy"
|
||||
msgstr "LEARN AUTO"
|
||||
|
||||
msgctxt "spell"
|
||||
msgid "reanimate"
|
||||
|
|
|
@ -93,7 +93,7 @@ email=$(grep "faction=$1:" reports.txt | cut -d: -f2 | sed 's/email=//')
|
|||
echo "sending reports to $1 / $email"
|
||||
info=/dev/null
|
||||
[ -e ../email.txt ] && info=../email.txt
|
||||
cat $info | mutt -F $ERESSEA/etc/muttrc -s "Testauswertung Spiel $game Partei $1" -a $zip -- $email
|
||||
cat $info | mutt -s "Testauswertung Spiel $game Partei $1" -a $zip -- $email
|
||||
}
|
||||
|
||||
game=0
|
||||
|
|
|
@ -5,6 +5,6 @@ import sys
|
|||
|
||||
def new_version(ver):
|
||||
os.system("git tag -f v%s" % ver)
|
||||
os.system("git push --tags")
|
||||
os.system("git push --tags -f")
|
||||
|
||||
new_version(sys.argv[1])
|
||||
|
|
|
@ -4,6 +4,7 @@ eressea.log.debug('rules for game E2')
|
|||
math.randomseed(rng.random())
|
||||
|
||||
local equipment = require('eressea.equipment')
|
||||
|
||||
local sets = {
|
||||
['seed_faction'] = {
|
||||
['items'] = {
|
||||
|
|
|
@ -1,13 +1,19 @@
|
|||
-- forward declaration required:
|
||||
|
||||
-- forward declarations required:
|
||||
local self = {}
|
||||
|
||||
local function equip_first(u)
|
||||
name = 'seed_' .. u.race
|
||||
equip_unit(u, name, 255)
|
||||
end
|
||||
|
||||
local mysets = {
|
||||
['first_unit'] = {
|
||||
['items'] = {
|
||||
['money'] = 2500,
|
||||
['log'] = 10,
|
||||
['stone'] = 4
|
||||
}
|
||||
},
|
||||
['callback'] = equip_first
|
||||
},
|
||||
['seed_unit'] = {
|
||||
['items'] = {
|
||||
|
@ -75,7 +81,7 @@ local mysets = {
|
|||
},
|
||||
['seed_insect'] = {
|
||||
['items'] = {
|
||||
['nestwarmth'] =9
|
||||
['nestwarmth'] = 9
|
||||
}
|
||||
},
|
||||
['seed_halfling'] = {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
require 'eressea.path'
|
||||
require 'eressea.resources'
|
||||
require 'eressea.equipment'
|
||||
require 'eressea.spells'
|
||||
|
||||
local self = {}
|
||||
|
|
|
@ -99,8 +99,6 @@ function self.update()
|
|||
r:set_resource("tree", trees * 1.1)
|
||||
msg:send_region(r)
|
||||
end
|
||||
if clear then
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
|
|
|
@ -6,5 +6,6 @@ package.path = package.path .. ';' .. path .. '/?.lua;' .. path .. '/?/init.lua'
|
|||
require 'eressea.path'
|
||||
require 'eressea'
|
||||
require 'eressea.xmlconf'
|
||||
|
||||
eressea.read_game(get_turn() .. ".dat")
|
||||
gmtool.editor()
|
||||
|
|
|
@ -338,45 +338,6 @@ function test_message()
|
|||
return msg
|
||||
end
|
||||
|
||||
function test_events()
|
||||
local fail = 1
|
||||
local function msg_handler(u, evt)
|
||||
str = evt:get(0)
|
||||
u2 = evt:get(1)
|
||||
assert(u2~=nil)
|
||||
assert(str=="Du Elf stinken")
|
||||
message_unit(u, u2, "thanks unit, i got your message: " .. str)
|
||||
message_faction(u, u2.faction, "thanks faction, i got your message: " .. str)
|
||||
message_region(u, "thanks region, i got your message: " .. str)
|
||||
fail = 0
|
||||
end
|
||||
|
||||
plain = region.create(0, 0, "plain")
|
||||
skill = 8
|
||||
|
||||
f = create_faction('elf')
|
||||
f.age = 20
|
||||
|
||||
u = unit.create(f, plain)
|
||||
u.number = 1
|
||||
u:add_item("money", u.number*100)
|
||||
u:clear_orders()
|
||||
u:add_order("NUMMER PARTEI test")
|
||||
u:add_handler("message", msg_handler)
|
||||
msg = "BOTSCHAFT EINHEIT " .. itoa36(u.id) .. " Du~Elf~stinken"
|
||||
f = create_faction('elf')
|
||||
f.age = 20
|
||||
|
||||
u = unit.create(f, plain)
|
||||
u.number = 1
|
||||
u:add_item("money", u.number*100)
|
||||
u:clear_orders()
|
||||
u:add_order("NUMMER PARTEI eviL")
|
||||
u:add_order(msg)
|
||||
process_orders()
|
||||
assert(fail==0)
|
||||
end
|
||||
|
||||
function test_renumber_ship()
|
||||
local r = region.create(0, 0, "plain")
|
||||
local f = create_faction('human')
|
||||
|
@ -1097,6 +1058,21 @@ function test_give_silver()
|
|||
assert_equal(10, u:get_item("money"))
|
||||
end
|
||||
|
||||
function test_build_castle_one_stage()
|
||||
local r = region.create(0, 0, 'plain')
|
||||
local f = faction.create('human')
|
||||
local u = unit.create(f, r, 2)
|
||||
|
||||
u:add_item('stone', 4)
|
||||
|
||||
u:set_skill('building', 1)
|
||||
u:add_order('MACHE BURG')
|
||||
|
||||
process_orders()
|
||||
assert_equal(2, u.building.size)
|
||||
assert_equal(2, u:get_item('stone'))
|
||||
end
|
||||
|
||||
function test_build_castle()
|
||||
local r = region.create(0, 0, "plain")
|
||||
local f = create_faction('human')
|
||||
|
|
|
@ -14,6 +14,42 @@ function test_read_race()
|
|||
assert_not_nil(f)
|
||||
end
|
||||
|
||||
function test_first_insect()
|
||||
local f = faction.create('insect')
|
||||
local r = region.create(0, 0, "plain")
|
||||
local u = unit.create(f, r, 1)
|
||||
u:equip('first_unit')
|
||||
assert_equal(9, u:get_item('nestwarmth'))
|
||||
end
|
||||
|
||||
function test_first_troll()
|
||||
local f = faction.create('troll')
|
||||
local r = region.create(0, 0, "plain")
|
||||
local u = unit.create(f, r, 1)
|
||||
u:equip('first_unit')
|
||||
assert_equal(2, u:eff_skill('perception'))
|
||||
end
|
||||
|
||||
function test_first_human()
|
||||
local f = faction.create('human')
|
||||
local r = region.create(0, 0, "plain")
|
||||
local u = unit.create(f, r, 1)
|
||||
u:equip('first_unit')
|
||||
assert_not_nil(u.building)
|
||||
assert_equal('castle', u.building.type)
|
||||
assert_equal(10, u.building.size)
|
||||
end
|
||||
|
||||
function test_first_aquarian()
|
||||
local f = faction.create('aquarian')
|
||||
local r = region.create(0, 0, "plain")
|
||||
local u = unit.create(f, r, 1)
|
||||
u:equip('first_unit')
|
||||
assert_not_nil(u.ship)
|
||||
assert_equal('boat', u.ship.type)
|
||||
assert_equal(1, u:get_skill('sailing'))
|
||||
end
|
||||
|
||||
function test_seed_unit()
|
||||
local r = region.create(0, 0, "plain")
|
||||
local f = faction.create('human')
|
||||
|
@ -37,3 +73,4 @@ function test_seed_elf()
|
|||
assert_equal('castle', u.building.type)
|
||||
assert_equal(10, u.building.size)
|
||||
end
|
||||
|
||||
|
|
|
@ -29,6 +29,21 @@ function test_castle_names()
|
|||
assert_equal("citadel", b:get_typename(6250))
|
||||
end
|
||||
|
||||
function test_build_castle_one_stage()
|
||||
local r = region.create(0, 0, 'plain')
|
||||
local f = faction.create('human')
|
||||
local u = unit.create(f, r, 2)
|
||||
|
||||
u:add_item('stone', 4)
|
||||
|
||||
u:set_skill('building', 1)
|
||||
u:add_order('MACHE BURG')
|
||||
|
||||
process_orders()
|
||||
assert_equal(2, u.building.size)
|
||||
assert_equal(2, u:get_item('stone'))
|
||||
end
|
||||
|
||||
function test_build_castle_stages()
|
||||
local r = region.create(0,0, "plain")
|
||||
local f = faction.create("human")
|
||||
|
|
|
@ -12,6 +12,30 @@ function setup()
|
|||
eressea.settings.set("rules.peasants.growth.factor", "0")
|
||||
end
|
||||
|
||||
function test_study_auto()
|
||||
local r = region.create(0, 0, "plain")
|
||||
local f = faction.create("human")
|
||||
local u = unit.create(f, r, 1)
|
||||
u:add_order("LERN AUT Waffenbau")
|
||||
assert_equal("LERNE AUTO Waffenbau", u:get_order(0))
|
||||
process_orders()
|
||||
assert_equal(1, u:get_skill("weaponsmithing"))
|
||||
end
|
||||
|
||||
function test_study_auto_expensive()
|
||||
local r = region.create(0, 0, "plain")
|
||||
local f = faction.create("human")
|
||||
local u = unit.create(f, r, 1)
|
||||
u:add_order("LERNE AUTO Magie")
|
||||
assert_equal("LERNE Magie", u:get_order(0))
|
||||
u:clear_orders()
|
||||
u:add_order("LERN AUT Taktik")
|
||||
assert_equal("LERNE Taktik", u:get_order(0))
|
||||
u:clear_orders()
|
||||
u:add_order("LERN AUT Waffenbau")
|
||||
assert_equal("LERNE AUTO Waffenbau", u:get_order(0))
|
||||
end
|
||||
|
||||
function test_calendar()
|
||||
assert_equal("winter", get_season(1011))
|
||||
assert_equal("spring", get_season(1012))
|
||||
|
@ -517,3 +541,16 @@ function test_buy_sell()
|
|||
assert_equal(4, u:get_item(item))
|
||||
assert_not_equal(0, u:get_item('money'))
|
||||
end
|
||||
|
||||
function test_seaserpent_attack()
|
||||
local r = region.create(0, 0, 'ocean')
|
||||
local sh = ship.create(r, 'boat')
|
||||
local us = unit.create(get_monsters(), r, 1, 'seaserpent')
|
||||
local u = unit.create(faction.create('human', 'enno@example.com'), r, 20, 'human')
|
||||
u.ship = sh
|
||||
us:clear_orders()
|
||||
us:add_order('ATTACKIERE ' .. itoa36(u.id))
|
||||
us:set_skill('unarmed', 10)
|
||||
process_orders()
|
||||
write_reports()
|
||||
end
|
||||
|
|
|
@ -42,7 +42,8 @@ function test_build_watch()
|
|||
process_orders()
|
||||
assert_not_nil(u.building)
|
||||
if 5 ~= u.building.size then
|
||||
for k,v in f.messages do
|
||||
-- debug logging to find intermittent errors
|
||||
for k,v in ipairs(f.messages) do
|
||||
print(v)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -93,11 +93,11 @@ end
|
|||
function test_lighthouse()
|
||||
eressea.free_game()
|
||||
local r = region.create(0, 0, "mountain")
|
||||
local f = faction.create("human", "noreply@eressea.de", "de")
|
||||
local f = faction.create("human", "human@example.com")
|
||||
region.create(1, 0, "mountain")
|
||||
region.create(2, 0, "ocean")
|
||||
region.create(0, 1, "firewall")
|
||||
region.create(3, 0, "mountain")
|
||||
region.create(3, 0, "ocean")
|
||||
region.create(4, 0, "plain")
|
||||
local u = unit.create(f, r, 1)
|
||||
local b = building.create(r, "lighthouse")
|
||||
|
@ -110,7 +110,7 @@ function test_lighthouse()
|
|||
|
||||
init_reports()
|
||||
write_report(f)
|
||||
assert_true(find_in_report(f, " %(1,0%) %(vom Turm erblickt%)"))
|
||||
assert_false(find_in_report(f, " %(1,0%) %(vom Turm erblickt%)"))
|
||||
assert_true(find_in_report(f, " %(2,0%) %(vom Turm erblickt%)"))
|
||||
assert_true(find_in_report(f, " %(3,0%) %(vom Turm erblickt%)"))
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ end
|
|||
|
||||
function test_study()
|
||||
local r = region.create(0, 0, "plain")
|
||||
local f = faction.create("human", "test@example.com", "de")
|
||||
local f = faction.create("human")
|
||||
local u = unit.create(f, r, 1)
|
||||
u:add_order("LERNEN Armbrust")
|
||||
process_orders()
|
||||
|
@ -33,7 +33,7 @@ end
|
|||
|
||||
function test_study_expensive()
|
||||
local r = region.create(0, 0, "plain")
|
||||
local f = faction.create("human", "test@example.com", "de")
|
||||
local f = faction.create("human")
|
||||
local u = unit.create(f, r, 1)
|
||||
eressea.settings.set("skills.cost.alchemy", "50")
|
||||
u:add_order("LERNEN Alchemie")
|
||||
|
@ -45,7 +45,7 @@ end
|
|||
|
||||
function test_unit_spells()
|
||||
local r = region.create(0, 0, "plain")
|
||||
local f = faction.create("human", "test@example.com", "de")
|
||||
local f = faction.create("human")
|
||||
local u = unit.create(f, r, 1)
|
||||
u.magic = "gray"
|
||||
u:set_skill("magic", 1)
|
||||
|
@ -75,7 +75,7 @@ end
|
|||
|
||||
function test_study_no_teacher()
|
||||
local r = region.create(0, 0, "plain")
|
||||
local f = faction.create("human", "test@example.com", "de")
|
||||
local f = faction.create("human")
|
||||
local u1 = make_student(f, r, 1)
|
||||
u1:set_skill("crossbow", 1)
|
||||
process_orders()
|
||||
|
@ -84,7 +84,7 @@ end
|
|||
|
||||
function test_study_with_teacher()
|
||||
local r = region.create(0, 0, "plain")
|
||||
local f = faction.create("human", "test@example.com", "de")
|
||||
local f = faction.create("human")
|
||||
local u1 = make_student(f, r, 1)
|
||||
|
||||
make_teacher(u1)
|
||||
|
@ -95,7 +95,7 @@ end
|
|||
|
||||
function test_study_too_many_students()
|
||||
local r = region.create(0, 0, "plain")
|
||||
local f = faction.create("human", "test@example.com", "de")
|
||||
local f = faction.create("human")
|
||||
local u1 = make_student(f, r, 20, "Taktik")
|
||||
u1.name = "Student"
|
||||
u1:add_item("money", 201*u1.number)
|
||||
|
@ -106,7 +106,7 @@ end
|
|||
|
||||
function test_study_multiple_teachers()
|
||||
local r = region.create(0, 0, "plain")
|
||||
local f = faction.create("human", "test@example.com", "de")
|
||||
local f = faction.create("human")
|
||||
local u1 = make_student(f, r, 20, "Taktik")
|
||||
u1.name = "Student"
|
||||
u1:add_item("money", 201*u1.number)
|
||||
|
|
BIN
src/.DS_Store
vendored
Normal file
BIN
src/.DS_Store
vendored
Normal file
Binary file not shown.
|
@ -86,6 +86,7 @@ ENDIF()
|
|||
|
||||
set (ERESSEA_SRC
|
||||
vortex.c
|
||||
automate.c
|
||||
move.c
|
||||
piracy.c
|
||||
spells.c
|
||||
|
@ -187,6 +188,7 @@ set(TESTS_SRC
|
|||
tests.c
|
||||
academy.test.c
|
||||
alchemy.test.c
|
||||
automate.test.c
|
||||
battle.test.c
|
||||
creport.test.c
|
||||
direction.test.c
|
||||
|
|
|
@ -33,13 +33,13 @@ void academy_teaching_bonus(struct unit *u, skill_t sk, int students) {
|
|||
}
|
||||
}
|
||||
|
||||
bool academy_can_teach(unit *teacher, unit *student, skill_t sk) {
|
||||
bool academy_can_teach(unit *teacher, unit *scholar, skill_t sk) {
|
||||
const struct building_type *btype = bt_find("academy");
|
||||
if (active_building(teacher, btype) && active_building(student, btype)) {
|
||||
int j = study_cost(student, sk) * 2;
|
||||
if (active_building(teacher, btype) && active_building(scholar, btype)) {
|
||||
int j = study_cost(scholar, sk) * 2;
|
||||
if (j < 50) j = 50;
|
||||
/* kann Einheit das zahlen? */
|
||||
return get_pooled(student, get_resourcetype(R_SILVER), GET_DEFAULT, j) >= j;
|
||||
return get_pooled(scholar, get_resourcetype(R_SILVER), GET_DEFAULT, j) >= j;
|
||||
/* sonst nehmen sie nicht am Unterricht teil */
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -9,7 +9,7 @@ extern "C" {
|
|||
|
||||
struct unit;
|
||||
void academy_teaching_bonus(struct unit *u, skill_t sk, int academy);
|
||||
bool academy_can_teach(struct unit *teacher, struct unit *student, skill_t sk);
|
||||
bool academy_can_teach(struct unit *teacher, struct unit *scholar, skill_t sk);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -26,7 +26,6 @@ static void test_herbsearch(CuTest * tc)
|
|||
const item_type *itype;
|
||||
|
||||
test_setup();
|
||||
test_inject_messagetypes();
|
||||
r = test_create_region(0, 0, NULL);
|
||||
rc = rc_get_or_create("dragon");
|
||||
rc->flags |= RCF_UNARMEDGUARD;
|
||||
|
|
|
@ -209,6 +209,7 @@ void register_attributes(void)
|
|||
|
||||
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 */
|
||||
at_deprecate("xontormiaexpress", a_readint); /* required for old datafiles */
|
||||
at_deprecate("orcification", a_readint); /* required for old datafiles */
|
||||
at_deprecate("lua", read_ext); /* required for old datafiles */
|
||||
|
|
163
src/automate.c
Normal file
163
src/automate.c
Normal file
|
@ -0,0 +1,163 @@
|
|||
#include <platform.h>
|
||||
|
||||
#include "kernel/faction.h"
|
||||
#include "kernel/messages.h"
|
||||
#include "kernel/order.h"
|
||||
#include "kernel/region.h"
|
||||
#include "kernel/unit.h"
|
||||
|
||||
#include "util/log.h"
|
||||
|
||||
#include "automate.h"
|
||||
#include "keyword.h"
|
||||
#include "laws.h"
|
||||
#include "study.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
static int cmp_scholars(const void *lhs, const void *rhs)
|
||||
{
|
||||
const scholar *a = (const scholar *)lhs;
|
||||
const scholar *b = (const scholar *)rhs;
|
||||
if (a->sk == b->sk) {
|
||||
/* sort by level, descending: */
|
||||
return b->level - a->level;
|
||||
}
|
||||
/* order by skill */
|
||||
return (int)a->sk - (int)b->sk;
|
||||
}
|
||||
|
||||
int autostudy_init(scholar scholars[], int max_scholars, region *r)
|
||||
{
|
||||
unit *u;
|
||||
int nscholars = 0;
|
||||
|
||||
for (u = r->units; u; u = u->next) {
|
||||
keyword_t kwd = init_order(u->thisorder, u->faction->locale);
|
||||
if (kwd == K_AUTOSTUDY) {
|
||||
if (long_order_allowed(u)) {
|
||||
scholar * st = scholars + nscholars;
|
||||
skill_t sk = getskill(u->faction->locale);
|
||||
if (check_student(u, u->thisorder, sk)) {
|
||||
st->sk = sk;
|
||||
st->level = effskill_study(u, st->sk);
|
||||
st->learn = 0;
|
||||
st->u = u;
|
||||
if (++nscholars == max_scholars) {
|
||||
log_fatal("you must increase MAXSCHOLARS");
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "error_race_nolearn", "race",
|
||||
u_race(u)));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nscholars > 0) {
|
||||
qsort(scholars, nscholars, sizeof(scholar), cmp_scholars);
|
||||
}
|
||||
return nscholars;
|
||||
}
|
||||
|
||||
static void teaching(scholar *s, int n) {
|
||||
assert(n <= s->u->number);
|
||||
s->learn += n;
|
||||
s->u->flags |= UFL_LONGACTION;
|
||||
}
|
||||
|
||||
static void learning(scholar *s, int n) {
|
||||
assert(n <= s->u->number);
|
||||
s->learn += n;
|
||||
s->u->flags |= UFL_LONGACTION;
|
||||
}
|
||||
|
||||
void autostudy_run(scholar scholars[], int nscholars)
|
||||
{
|
||||
int ti = 0;
|
||||
while (ti != nscholars) {
|
||||
skill_t sk = scholars[ti].sk;
|
||||
int t, s, se, ts = 0, tt = 0, si = ti;
|
||||
for (se = ti; se != nscholars && scholars[se].sk == sk; ++se) {
|
||||
int mint;
|
||||
ts += scholars[se].u->number; /* count total scholars */
|
||||
mint = (ts + 10) / 11; /* need a minimum of ceil(ts/11) teachers */
|
||||
for (; mint > tt && si != nscholars && scholars[si].sk == sk; ++si) {
|
||||
tt += scholars[si].u->number;
|
||||
}
|
||||
}
|
||||
/* now si splits the teachers and students 1:10 */
|
||||
/* first student must be 2 levels below first teacher: */
|
||||
for (; si != se && scholars[ti].level - TEACHDIFFERENCE > scholars[si].level && scholars[si].sk == sk; ++si) {
|
||||
tt += scholars[si].u->number;
|
||||
}
|
||||
if (si == se) {
|
||||
/* there are no students, so standard learning only */
|
||||
for (t = ti; t != se; ++t) {
|
||||
learning(scholars + t, scholars[t].u->number);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* invariant: unit ti can still teach i students */
|
||||
int i = scholars[ti].u->number * STUDENTS_PER_TEACHER;
|
||||
/* invariant: unit si has n students that can still be taught */
|
||||
int n = scholars[si].u->number;
|
||||
for (t = ti, s = si; t != si && s != se; ) {
|
||||
if (i > n) {
|
||||
/* t has more than enough teaching capacity for s */
|
||||
i -= n;
|
||||
teaching(scholars + s, n);
|
||||
learning(scholars + s, scholars[s].u->number);
|
||||
/* next student, please: */
|
||||
if (++s == se) {
|
||||
continue;
|
||||
}
|
||||
n = scholars[s].u->number;
|
||||
}
|
||||
else {
|
||||
/* s gets partial credit and we need a new teacher */
|
||||
teaching(scholars + s, i);
|
||||
|
||||
/* we are done with this teacher. any remaining people are regular learners: */
|
||||
if (scholars[t].u->number > 1) {
|
||||
/* remain = number - ceil(taught/10); */
|
||||
int remain = (STUDENTS_PER_TEACHER * scholars[t].u->number - i + STUDENTS_PER_TEACHER - 1) / STUDENTS_PER_TEACHER;
|
||||
learning(scholars + t, remain);
|
||||
}
|
||||
|
||||
/* we want a new teacher for s. if any exists, it's next in the sequence. */
|
||||
if (++t == si) {
|
||||
continue;
|
||||
}
|
||||
if (scholars[t].level - TEACHDIFFERENCE < scholars[s].level) {
|
||||
/* next teacher cannot teach, we must skip students. */
|
||||
do {
|
||||
learning(scholars + s, (n - i));
|
||||
i = 0;
|
||||
if (++s == se) {
|
||||
break;
|
||||
}
|
||||
n = scholars[s].u->number;
|
||||
} while (scholars[t].level - TEACHDIFFERENCE < scholars[s].level);
|
||||
}
|
||||
i = scholars[t].u->number * STUDENTS_PER_TEACHER;
|
||||
}
|
||||
}
|
||||
}
|
||||
ti = se;
|
||||
}
|
||||
}
|
||||
|
||||
#define MAXSCHOLARS 128
|
||||
|
||||
void do_autostudy(region *r)
|
||||
{
|
||||
scholar scholars[MAXSCHOLARS];
|
||||
int i, nscholars = autostudy_init(scholars, MAXSCHOLARS, r);
|
||||
autostudy_run(scholars, nscholars);
|
||||
for (i = 0; i != nscholars; ++i) {
|
||||
int days = STUDYDAYS * scholars[i].learn;
|
||||
learn_skill(scholars[i].u, scholars[i].sk, days);
|
||||
}
|
||||
}
|
43
src/automate.h
Normal file
43
src/automate.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
Copyright (c) 1998-2018, Enno Rehling <enno@eressea.de>
|
||||
Katja Zedel <katze@felidae.kn-bremen.de
|
||||
Christian Schlittchen <corwin@amber.kn-bremen.de>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef H_GC_AUTOMATE
|
||||
#define H_GC_AUTOMATE
|
||||
|
||||
#include "skill.h"
|
||||
|
||||
struct region;
|
||||
struct unit;
|
||||
|
||||
typedef struct scholar {
|
||||
struct unit *u;
|
||||
skill_t sk;
|
||||
int level;
|
||||
int learn;
|
||||
} scholar;
|
||||
|
||||
#define STUDENTS_PER_TEACHER 10
|
||||
|
||||
void do_autostudy(struct region *r);
|
||||
|
||||
int autostudy_init(scholar scholars[], int max_scholars, struct region *r);
|
||||
void autostudy_run(scholar scholars[], int nscholars);
|
||||
|
||||
#endif
|
122
src/automate.test.c
Normal file
122
src/automate.test.c
Normal file
|
@ -0,0 +1,122 @@
|
|||
#ifdef _MSC_VER
|
||||
#include <platform.h>
|
||||
#endif
|
||||
|
||||
#include "automate.h"
|
||||
|
||||
#include "kernel/faction.h"
|
||||
#include "kernel/order.h"
|
||||
#include "kernel/region.h"
|
||||
#include "kernel/unit.h"
|
||||
|
||||
#include "util/message.h"
|
||||
|
||||
#include "tests.h"
|
||||
|
||||
#include <CuTest.h>
|
||||
|
||||
static void test_autostudy_init(CuTest *tc) {
|
||||
scholar scholars[4];
|
||||
unit *u1, *u2, *u3, *u4;
|
||||
faction *f;
|
||||
region *r;
|
||||
|
||||
test_setup();
|
||||
mt_create_error(77);
|
||||
mt_create_error(771);
|
||||
|
||||
r = test_create_plain(0, 0);
|
||||
f = test_create_faction(NULL);
|
||||
u1 = test_create_unit(f, r);
|
||||
u1->thisorder = create_order(K_AUTOSTUDY, f->locale, skillnames[SK_ENTERTAINMENT]);
|
||||
test_create_unit(f, r);
|
||||
u2 = test_create_unit(f, r);
|
||||
u2->thisorder = create_order(K_AUTOSTUDY, f->locale, skillnames[SK_ENTERTAINMENT]);
|
||||
set_level(u2, SK_ENTERTAINMENT, 2);
|
||||
u3 = test_create_unit(f, r);
|
||||
u3->thisorder = create_order(K_AUTOSTUDY, f->locale, skillnames[SK_PERCEPTION]);
|
||||
u4 = test_create_unit(test_create_faction(NULL), r);
|
||||
u4->thisorder = create_order(K_AUTOSTUDY, f->locale, "Dudelidu");
|
||||
scholars[3].u = NULL;
|
||||
CuAssertIntEquals(tc, 3, autostudy_init(scholars, 4, r));
|
||||
CuAssertPtrNotNull(tc, test_find_messagetype(u4->faction->msgs, "error77"));
|
||||
CuAssertPtrEquals(tc, u2, scholars[0].u);
|
||||
CuAssertIntEquals(tc, 2, scholars[0].level);
|
||||
CuAssertIntEquals(tc, 0, scholars[0].learn);
|
||||
CuAssertIntEquals(tc, SK_ENTERTAINMENT, scholars[0].sk);
|
||||
CuAssertPtrEquals(tc, u1, scholars[1].u);
|
||||
CuAssertIntEquals(tc, 0, scholars[1].level);
|
||||
CuAssertIntEquals(tc, 0, scholars[1].learn);
|
||||
CuAssertIntEquals(tc, SK_ENTERTAINMENT, scholars[1].sk);
|
||||
CuAssertPtrEquals(tc, u3, scholars[2].u);
|
||||
CuAssertIntEquals(tc, 0, scholars[2].level);
|
||||
CuAssertIntEquals(tc, 0, scholars[2].learn);
|
||||
CuAssertIntEquals(tc, SK_PERCEPTION, scholars[2].sk);
|
||||
CuAssertPtrEquals(tc, NULL, scholars[3].u);
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
static void test_autostudy_run(CuTest *tc) {
|
||||
scholar scholars[4];
|
||||
unit *u1, *u2, *u3;
|
||||
faction *f;
|
||||
region *r;
|
||||
|
||||
test_setup();
|
||||
r = test_create_plain(0, 0);
|
||||
f = test_create_faction(NULL);
|
||||
u1 = test_create_unit(f, r);
|
||||
u1->thisorder = create_order(K_AUTOSTUDY, f->locale, skillnames[SK_ENTERTAINMENT]);
|
||||
set_number(u1, 2);
|
||||
set_level(u1, SK_ENTERTAINMENT, 2);
|
||||
u2 = test_create_unit(f, r);
|
||||
u2->thisorder = create_order(K_AUTOSTUDY, f->locale, skillnames[SK_ENTERTAINMENT]);
|
||||
set_number(u2, 10);
|
||||
u3 = test_create_unit(f, r);
|
||||
u3->thisorder = create_order(K_AUTOSTUDY, f->locale, skillnames[SK_PERCEPTION]);
|
||||
set_number(u3, 15);
|
||||
scholars[3].u = NULL;
|
||||
CuAssertIntEquals(tc, 3, autostudy_init(scholars, 4, r));
|
||||
autostudy_run(scholars, 3);
|
||||
CuAssertIntEquals(tc, 0, scholars[0].learn);
|
||||
CuAssertIntEquals(tc, 20, scholars[1].learn);
|
||||
CuAssertIntEquals(tc, 15, scholars[2].learn);
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
static void test_autostudy_run_noteachers(CuTest *tc) {
|
||||
scholar scholars[4];
|
||||
unit *u1, *u2, *u3;
|
||||
faction *f;
|
||||
region *r;
|
||||
|
||||
test_setup();
|
||||
r = test_create_plain(0, 0);
|
||||
f = test_create_faction(NULL);
|
||||
u1 = test_create_unit(f, r);
|
||||
u1->thisorder = create_order(K_AUTOSTUDY, f->locale, skillnames[SK_LUMBERJACK]);
|
||||
set_number(u1, 2);
|
||||
set_level(u1, SK_ENTERTAINMENT, 2);
|
||||
u2 = test_create_unit(f, r);
|
||||
u2->thisorder = create_order(K_AUTOSTUDY, f->locale, skillnames[SK_ENTERTAINMENT]);
|
||||
set_number(u2, 10);
|
||||
u3 = test_create_unit(f, r);
|
||||
u3->thisorder = create_order(K_AUTOSTUDY, f->locale, skillnames[SK_PERCEPTION]);
|
||||
set_number(u3, 15);
|
||||
scholars[3].u = NULL;
|
||||
CuAssertIntEquals(tc, 3, autostudy_init(scholars, 4, r));
|
||||
autostudy_run(scholars, 3);
|
||||
CuAssertIntEquals(tc, 2, scholars[0].learn);
|
||||
CuAssertIntEquals(tc, 10, scholars[1].learn);
|
||||
CuAssertIntEquals(tc, 15, scholars[2].learn);
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
CuSuite *get_automate_suite(void)
|
||||
{
|
||||
CuSuite *suite = CuSuiteNew();
|
||||
SUITE_ADD_TEST(suite, test_autostudy_init);
|
||||
SUITE_ADD_TEST(suite, test_autostudy_run);
|
||||
SUITE_ADD_TEST(suite, test_autostudy_run_noteachers);
|
||||
return suite;
|
||||
}
|
|
@ -20,13 +20,13 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
#include <kernel/config.h>
|
||||
#include "battle.h"
|
||||
#include "alchemy.h"
|
||||
#include "chaos.h"
|
||||
#include "guard.h"
|
||||
#include "laws.h"
|
||||
#include "monsters.h"
|
||||
#include "move.h"
|
||||
#include "skill.h"
|
||||
#include "study.h"
|
||||
#include "spy.h"
|
||||
|
||||
#include <spells/buildingcurse.h>
|
||||
#include <spells/regioncurse.h>
|
||||
|
@ -2531,7 +2531,6 @@ static void battle_effects(battle * b, int dead_players)
|
|||
}
|
||||
if (dead_peasants) {
|
||||
deathcounts(r, dead_peasants + dead_players);
|
||||
add_chaoscount(r, dead_peasants / 2);
|
||||
rsetpeasants(r, rp - dead_peasants);
|
||||
}
|
||||
}
|
||||
|
@ -2789,10 +2788,12 @@ static void aftermath(battle * b)
|
|||
ship *sh = *sp;
|
||||
freset(sh, SF_DAMAGED);
|
||||
if (sh->damage >= sh->size * DAMAGE_SCALE) {
|
||||
sink_ship(sh);
|
||||
remove_ship(sp, sh);
|
||||
}
|
||||
if (*sp == sh)
|
||||
else {
|
||||
sp = &sh->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3325,7 +3326,7 @@ fighter * get_fighter(battle * b, const struct unit * u)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int join_battle(battle * b, unit * u, bool attack, fighter ** cp)
|
||||
int join_battle(battle * b, unit * u, bool attack, fighter ** cp)
|
||||
{
|
||||
side *s;
|
||||
fighter *fc = NULL;
|
||||
|
|
|
@ -261,6 +261,7 @@ extern "C" {
|
|||
void free_battle(struct battle * b);
|
||||
struct fighter *make_fighter(struct battle *b, struct unit *u,
|
||||
struct side * s, bool attack);
|
||||
int join_battle(struct battle * b, struct unit * u, bool attack, struct fighter ** cp);
|
||||
struct side *make_side(struct battle * b, const struct faction * f,
|
||||
const struct group * g, unsigned int flags,
|
||||
const struct faction * stealthfaction);
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#include <platform.h>
|
||||
|
||||
#include "battle.h"
|
||||
|
||||
#include "reports.h"
|
||||
#include "skill.h"
|
||||
|
||||
#include <kernel/config.h>
|
||||
|
@ -16,6 +18,8 @@
|
|||
#include <spells/buildingcurse.h>
|
||||
|
||||
#include <util/functions.h>
|
||||
#include <util/language.h>
|
||||
#include <util/message.h>
|
||||
#include <util/rand.h>
|
||||
#include <util/rng.h>
|
||||
#include <util/strings.h>
|
||||
|
@ -552,6 +556,103 @@ static void test_battle_skilldiff(CuTest *tc)
|
|||
test_teardown();
|
||||
}
|
||||
|
||||
static void test_battle_report_one(CuTest *tc)
|
||||
{
|
||||
battle * b = NULL;
|
||||
region *r;
|
||||
unit *u1, *u2;
|
||||
message *m;
|
||||
const char *expect;
|
||||
fighter *fig;
|
||||
|
||||
test_setup();
|
||||
mt_create_va(mt_new("start_battle", NULL), "factions:string", MT_NEW_END);
|
||||
r = test_create_plain(0, 0);
|
||||
u1 = test_create_unit(test_create_faction(NULL), r);
|
||||
u2 = test_create_unit(test_create_faction(NULL), r);
|
||||
b = make_battle(r);
|
||||
join_battle(b, u1, true, &fig);
|
||||
join_battle(b, u2, false, &fig);
|
||||
faction_setname(u1->faction, "Monster");
|
||||
expect = factionname(u1->faction);
|
||||
|
||||
report_battle_start(b);
|
||||
CuAssertPtrNotNull(tc, m = test_find_messagetype(u1->faction->battles->msgs, "start_battle"));
|
||||
CuAssertStrEquals(tc, expect, (const char *)m->parameters[0].v);
|
||||
|
||||
free_battle(b);
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
static void test_battle_report_two(CuTest *tc)
|
||||
{
|
||||
battle * b = NULL;
|
||||
region *r;
|
||||
unit *u1, *u2;
|
||||
message *m;
|
||||
char expect[64];
|
||||
fighter *fig;
|
||||
struct locale *lang;
|
||||
|
||||
test_setup();
|
||||
lang = test_create_locale();
|
||||
locale_setstring(lang, "and", "and");
|
||||
mt_create_va(mt_new("start_battle", NULL), "factions:string", MT_NEW_END);
|
||||
r = test_create_plain(0, 0);
|
||||
u1 = test_create_unit(test_create_faction(NULL), r);
|
||||
u1->faction->locale = lang;
|
||||
u2 = test_create_unit(test_create_faction(NULL), r);
|
||||
u2->faction->locale = lang;
|
||||
|
||||
str_slprintf(expect, sizeof(expect), "%s and %s", factionname(u1->faction), factionname(u2->faction));
|
||||
b = make_battle(r);
|
||||
join_battle(b, u1, true, &fig);
|
||||
join_battle(b, u2, true, &fig);
|
||||
report_battle_start(b);
|
||||
|
||||
CuAssertPtrNotNull(tc, m = test_find_messagetype(u1->faction->battles->msgs, "start_battle"));
|
||||
CuAssertStrEquals(tc, expect, (const char *)m->parameters[0].v);
|
||||
|
||||
free_battle(b);
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
static void test_battle_report_three(CuTest *tc)
|
||||
{
|
||||
battle * b = NULL;
|
||||
region *r;
|
||||
unit *u1, *u2, *u3;
|
||||
message *m;
|
||||
char expect[64];
|
||||
fighter *fig;
|
||||
struct locale *lang;
|
||||
|
||||
test_setup();
|
||||
lang = test_create_locale();
|
||||
locale_setstring(lang, "and", "and");
|
||||
mt_create_va(mt_new("start_battle", NULL), "factions:string", MT_NEW_END);
|
||||
r = test_create_plain(0, 0);
|
||||
u1 = test_create_unit(test_create_faction(NULL), r);
|
||||
u1->faction->locale = lang;
|
||||
u2 = test_create_unit(test_create_faction(NULL), r);
|
||||
u2->faction->locale = lang;
|
||||
u3 = test_create_unit(test_create_faction(NULL), r);
|
||||
u3->faction->locale = lang;
|
||||
|
||||
str_slprintf(expect, sizeof(expect), "%s, %s and %s", factionname(u1->faction), factionname(u2->faction), factionname(u3->faction));
|
||||
b = make_battle(r);
|
||||
join_battle(b, u1, true, &fig);
|
||||
join_battle(b, u2, true, &fig);
|
||||
join_battle(b, u3, true, &fig);
|
||||
report_battle_start(b);
|
||||
|
||||
CuAssertPtrNotNull(tc, m = test_find_messagetype(u1->faction->battles->msgs, "start_battle"));
|
||||
CuAssertStrEquals(tc, expect, (const char *)m->parameters[0].v);
|
||||
|
||||
free_battle(b);
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
static void test_battle_skilldiff_building(CuTest *tc)
|
||||
{
|
||||
troop ta, td;
|
||||
|
@ -690,6 +791,9 @@ CuSuite *get_battle_suite(void)
|
|||
SUITE_ADD_TEST(suite, test_select_armor);
|
||||
SUITE_ADD_TEST(suite, test_battle_skilldiff);
|
||||
SUITE_ADD_TEST(suite, test_battle_skilldiff_building);
|
||||
SUITE_ADD_TEST(suite, test_battle_report_one);
|
||||
SUITE_ADD_TEST(suite, test_battle_report_two);
|
||||
SUITE_ADD_TEST(suite, test_battle_report_three);
|
||||
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);
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#include "bind_ship.h"
|
||||
#include "bind_building.h"
|
||||
|
||||
#include "chaos.h"
|
||||
#include "teleport.h"
|
||||
|
||||
#include <kernel/calendar.h>
|
||||
|
@ -356,7 +355,7 @@ static int tolua_region_get_resourcelevel(lua_State * L)
|
|||
#define LUA_ASSERT(c, s) if (!(c)) { log_error("%s(%d): %s\n", __FILE__, __LINE__, (s)); return 0; }
|
||||
|
||||
static int special_resource(const char *type) {
|
||||
const char * special[] = { "seed", "sapling", "tree", "grave", "chaos", 0 };
|
||||
const char * special[] = { "seed", "sapling", "tree", "grave", NULL };
|
||||
int i;
|
||||
|
||||
for (i = 0; special[i]; ++i) {
|
||||
|
@ -389,9 +388,6 @@ static int tolua_region_get_resource(lua_State * L)
|
|||
case 3:
|
||||
result = deathcount(r);
|
||||
break;
|
||||
case 4:
|
||||
result = get_chaoscount(r);
|
||||
break;
|
||||
default:
|
||||
rtype = rt_find(type);
|
||||
if (rtype) {
|
||||
|
@ -423,9 +419,6 @@ static int tolua_region_set_resource(lua_State * L)
|
|||
case 3:
|
||||
deathcounts(r, value - deathcount(r));
|
||||
break;
|
||||
case 4:
|
||||
add_chaoscount(r, value - get_chaoscount(r));
|
||||
break;
|
||||
default:
|
||||
rtype = rt_find(type);
|
||||
if (rtype != NULL) {
|
||||
|
|
|
@ -455,48 +455,6 @@ int fctr_handle(struct trigger *tp, void *data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void fctr_init(trigger * t)
|
||||
{
|
||||
t->data.v = calloc(sizeof(fctr_data), 1);
|
||||
}
|
||||
|
||||
static void fctr_done(trigger * t)
|
||||
{
|
||||
fctr_data *fd = (fctr_data *)t->data.v;
|
||||
lua_State *L = (lua_State *)global.vm_state;
|
||||
luaL_unref(L, LUA_REGISTRYINDEX, fd->fhandle);
|
||||
free(fd);
|
||||
}
|
||||
|
||||
static struct trigger_type tt_lua = {
|
||||
"lua_event",
|
||||
fctr_init,
|
||||
fctr_done,
|
||||
fctr_handle
|
||||
};
|
||||
|
||||
static trigger *trigger_lua(struct unit *u, int handle)
|
||||
{
|
||||
trigger *t = t_new(&tt_lua);
|
||||
fctr_data *td = (fctr_data *)t->data.v;
|
||||
td->target = u;
|
||||
td->fhandle = handle;
|
||||
return t;
|
||||
}
|
||||
|
||||
static int tolua_unit_addhandler(lua_State * L)
|
||||
{
|
||||
unit *self = (unit *)tolua_tousertype(L, 1, 0);
|
||||
const char *ename = tolua_tostring(L, 2, 0);
|
||||
int handle;
|
||||
|
||||
lua_pushvalue(L, 3);
|
||||
handle = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||
add_trigger(&self->attribs, ename, trigger_lua(self, handle));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tolua_unit_addnotice(lua_State * L)
|
||||
{
|
||||
unit *self = (unit *)tolua_tousertype(L, 1, 0);
|
||||
|
@ -909,8 +867,8 @@ static int tolua_unit_create(lua_State * L)
|
|||
faction *f = (faction *)tolua_tousertype(L, 1, 0);
|
||||
region *r = (region *)tolua_tousertype(L, 2, 0);
|
||||
unit *u;
|
||||
const char *rcname = tolua_tostring(L, 4, NULL);
|
||||
int num = (int)tolua_tonumber(L, 3, 1);
|
||||
const char *rcname = tolua_tostring(L, 4, NULL);
|
||||
const race *rc;
|
||||
|
||||
assert(f && r);
|
||||
|
@ -1046,9 +1004,6 @@ void tolua_unit_open(lua_State * L)
|
|||
|
||||
tolua_function(L, TOLUA_CAST "add_notice", tolua_unit_addnotice);
|
||||
|
||||
/* npc logic: */
|
||||
tolua_function(L, TOLUA_CAST "add_handler", tolua_unit_addhandler);
|
||||
|
||||
tolua_variable(L, TOLUA_CAST "race_name", tolua_unit_get_racename,
|
||||
tolua_unit_set_racename);
|
||||
tolua_function(L, TOLUA_CAST "add_spell", tolua_unit_addspell);
|
||||
|
|
81
src/chaos.c
81
src/chaos.c
|
@ -21,6 +21,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
#include "chaos.h"
|
||||
#include "monsters.h"
|
||||
#include "move.h"
|
||||
#include "spy.h"
|
||||
|
||||
#include <kernel/building.h>
|
||||
#include <kernel/faction.h>
|
||||
|
@ -39,57 +40,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
/*********************/
|
||||
/* at_chaoscount */
|
||||
/*********************/
|
||||
attrib_type at_chaoscount = {
|
||||
"chaoscount",
|
||||
DEFAULT_INIT,
|
||||
DEFAULT_FINALIZE,
|
||||
DEFAULT_AGE,
|
||||
a_writeint,
|
||||
a_readint,
|
||||
NULL,
|
||||
ATF_UNIQUE
|
||||
};
|
||||
|
||||
void set_chaoscount(struct region *r, int deaths)
|
||||
{
|
||||
if (deaths==0) {
|
||||
a_removeall(&r->attribs, &at_chaoscount);
|
||||
} else {
|
||||
attrib *a = a_find(r->attribs, &at_chaoscount);
|
||||
if (!a) {
|
||||
a = a_add(&r->attribs, a_new(&at_chaoscount));
|
||||
}
|
||||
a->data.i = deaths;
|
||||
}
|
||||
}
|
||||
|
||||
int get_chaoscount(const region * r)
|
||||
{
|
||||
attrib *a = a_find(r->attribs, &at_chaoscount);
|
||||
if (!a)
|
||||
return 0;
|
||||
return a->data.i;
|
||||
}
|
||||
|
||||
void add_chaoscount(region * r, int fallen)
|
||||
{
|
||||
attrib *a;
|
||||
|
||||
if (fallen == 0)
|
||||
return;
|
||||
|
||||
a = a_find(r->attribs, &at_chaoscount);
|
||||
if (!a)
|
||||
a = a_add(&r->attribs, a_new(&at_chaoscount));
|
||||
a->data.i += fallen;
|
||||
|
||||
if (a->data.i <= 0)
|
||||
a_remove(&r->attribs, a);
|
||||
}
|
||||
|
||||
static const terrain_type *chaosterrain(void)
|
||||
{
|
||||
static const terrain_type **types;
|
||||
|
@ -195,19 +145,20 @@ static void chaos(region * r)
|
|||
break;
|
||||
}
|
||||
if (dir != MAXDIRECTIONS) {
|
||||
ship *sh = r->ships;
|
||||
ship **slist = &r->ships;
|
||||
unit **up;
|
||||
|
||||
while (sh) {
|
||||
ship *nsh = sh->next;
|
||||
double dmg =
|
||||
config_get_flt("rules.ship.damage.atlantis",
|
||||
0.50);
|
||||
damage_ship(sh, dmg);
|
||||
while (*slist) {
|
||||
ship *sh = *slist;
|
||||
|
||||
damage_ship(sh, 0.5);
|
||||
if (sh->damage >= sh->size * DAMAGE_SCALE) {
|
||||
remove_ship(&sh->region->ships, sh);
|
||||
sink_ship(sh);
|
||||
remove_ship(slist, sh);
|
||||
}
|
||||
else {
|
||||
slist = &sh->next;
|
||||
}
|
||||
sh = nsh;
|
||||
}
|
||||
|
||||
for (up = &r->units; *up;) {
|
||||
|
@ -248,18 +199,8 @@ void chaos_update(void) {
|
|||
region *r;
|
||||
/* Chaos */
|
||||
for (r = regions; r; r = r->next) {
|
||||
int i;
|
||||
|
||||
if ((r->flags & RF_CHAOTIC)) {
|
||||
chaos(r);
|
||||
}
|
||||
i = get_chaoscount(r);
|
||||
if (i) {
|
||||
add_chaoscount(r, -(int)(i * ((double)(rng_int() % 10)) / 100.0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void chaos_register(void) {
|
||||
at_register(&at_chaoscount);
|
||||
}
|
||||
|
|
|
@ -22,17 +22,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct region;
|
||||
|
||||
extern struct attrib_type at_chaoscount;
|
||||
|
||||
void chaos_register(void);
|
||||
void chaos_update(void);
|
||||
|
||||
void set_chaoscount(struct region *r, int deaths);
|
||||
int get_chaoscount(const struct region * r);
|
||||
void add_chaoscount(struct region * r, int deaths);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1529,6 +1529,7 @@ static void report_itemtype(FILE *F, faction *f, const item_type *itype) {
|
|||
fprintf(F, "\"%s\"\n", translate(ch, LOC(f->locale, ch)));
|
||||
m++;
|
||||
}
|
||||
assert(!m->rtype);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
158
src/economy.c
158
src/economy.c
|
@ -426,6 +426,59 @@ static int recruit_cost(const faction * f, const race * rc)
|
|||
return -1;
|
||||
}
|
||||
|
||||
message *can_recruit(unit *u, const race *rc, order *ord, int now)
|
||||
{
|
||||
region *r = u->region;
|
||||
|
||||
/* this is a very special case because the recruiting unit may be empty
|
||||
* at this point and we have to look at the creating unit instead. This
|
||||
* is done in cansee, which is called indirectly by is_guarded(). */
|
||||
if (is_guarded(r, u)) {
|
||||
return msg_error(u, ord, 70);
|
||||
}
|
||||
|
||||
if (rc == get_race(RC_INSECT)) {
|
||||
gamedate date;
|
||||
get_gamedate(now, &date);
|
||||
if (date.season == SEASON_WINTER && r->terrain != newterrain(T_DESERT)) {
|
||||
bool usepotion = false;
|
||||
unit *u2;
|
||||
|
||||
for (u2 = r->units; u2; u2 = u2->next) {
|
||||
if (fval(u2, UFL_WARMTH)) {
|
||||
usepotion = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!usepotion) {
|
||||
return msg_error(u, ord, 98);
|
||||
}
|
||||
}
|
||||
/* in Gletschern, Eisbergen gar nicht rekrutieren */
|
||||
if (r_insectstalled(r)) {
|
||||
return msg_error(u, ord, 97);
|
||||
}
|
||||
}
|
||||
if (is_cursed(r->attribs, &ct_riotzone)) {
|
||||
/* Die Region befindet sich in Aufruhr */
|
||||
return msg_error(u, ord, 237);
|
||||
}
|
||||
|
||||
if (rc && !playerrace(rc)) {
|
||||
return msg_error(u, ord, 139);
|
||||
}
|
||||
|
||||
if (fval(u, UFL_HERO)) {
|
||||
return msg_feedback(u, ord, "error_herorecruit", "");
|
||||
}
|
||||
if (has_skill(u, SK_MAGIC)) {
|
||||
/* error158;de;{unit} in {region}: '{command}' - Magier arbeiten
|
||||
* grunds<EFBFBD>tzlich nur alleine! */
|
||||
return msg_error(u, ord, 158);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void recruit(unit * u, struct order *ord, econ_request ** recruitorders)
|
||||
{
|
||||
region *r = u->region;
|
||||
|
@ -434,6 +487,7 @@ static void recruit(unit * u, struct order *ord, econ_request ** recruitorders)
|
|||
const faction *f = u->faction;
|
||||
const struct race *rc = u_race(u);
|
||||
int n;
|
||||
message *msg;
|
||||
|
||||
init_order_depr(ord);
|
||||
n = getint();
|
||||
|
@ -456,6 +510,7 @@ static void recruit(unit * u, struct order *ord, econ_request ** recruitorders)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (recruitcost < 0) {
|
||||
rc = u_race(u);
|
||||
recruitcost = recruit_cost(f, rc);
|
||||
|
@ -463,95 +518,46 @@ static void recruit(unit * u, struct order *ord, econ_request ** recruitorders)
|
|||
recruitcost = INT_MAX;
|
||||
}
|
||||
}
|
||||
assert(rc);
|
||||
u_setrace(u, rc);
|
||||
|
||||
/* this is a very special case because the recruiting unit may be empty
|
||||
* at this point and we have to look at the creating unit instead. This
|
||||
* is done in cansee, which is called indirectly by is_guarded(). */
|
||||
if (is_guarded(r, u)) {
|
||||
cmistake(u, ord, 70, MSG_EVENT);
|
||||
return;
|
||||
}
|
||||
|
||||
if (rc == get_race(RC_INSECT)) {
|
||||
gamedate date;
|
||||
get_gamedate(turn, &date);
|
||||
if (date.season == 0 && r->terrain != newterrain(T_DESERT)) {
|
||||
bool usepotion = false;
|
||||
unit *u2;
|
||||
|
||||
for (u2 = r->units; u2; u2 = u2->next)
|
||||
if (fval(u2, UFL_WARMTH)) {
|
||||
usepotion = true;
|
||||
break;
|
||||
}
|
||||
if (!usepotion)
|
||||
{
|
||||
cmistake(u, ord, 98, MSG_EVENT);
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* in Gletschern, Eisbergen gar nicht rekrutieren */
|
||||
if (r_insectstalled(r)) {
|
||||
cmistake(u, ord, 97, MSG_EVENT);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (is_cursed(r->attribs, &ct_riotzone)) {
|
||||
/* Die Region befindet sich in Aufruhr */
|
||||
cmistake(u, ord, 237, MSG_EVENT);
|
||||
return;
|
||||
}
|
||||
|
||||
if (recruitcost) {
|
||||
if (recruitcost > 0) {
|
||||
int pool;
|
||||
plane *pl = getplane(r);
|
||||
if (pl && fval(pl, PFL_NORECRUITS)) {
|
||||
|
||||
if (pl && (pl->flags & PFL_NORECRUITS)) {
|
||||
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_pflnorecruit", ""));
|
||||
return;
|
||||
}
|
||||
|
||||
if (get_pooled(u, get_resourcetype(R_SILVER), GET_DEFAULT,
|
||||
recruitcost) < recruitcost) {
|
||||
pool = get_pooled(u, get_resourcetype(R_SILVER), GET_DEFAULT, recruitcost * n);
|
||||
if (pool < recruitcost) {
|
||||
cmistake(u, ord, 142, MSG_EVENT);
|
||||
return;
|
||||
}
|
||||
pool /= recruitcost;
|
||||
if (n > pool) n = pool;
|
||||
}
|
||||
if (!playerrace(rc)) {
|
||||
cmistake(u, ord, 139, MSG_EVENT);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fval(u, UFL_HERO)) {
|
||||
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_herorecruit", ""));
|
||||
return;
|
||||
}
|
||||
if (has_skill(u, SK_MAGIC)) {
|
||||
/* error158;de;{unit} in {region}: '{command}' - Magier arbeiten
|
||||
* grunds<EFBFBD>tzlich nur alleine! */
|
||||
cmistake(u, ord, 158, MSG_EVENT);
|
||||
return;
|
||||
}
|
||||
if (has_skill(u, SK_ALCHEMY)
|
||||
&& count_skill(u->faction, SK_ALCHEMY) + n >
|
||||
skill_limit(u->faction, SK_ALCHEMY)) {
|
||||
cmistake(u, ord, 156, MSG_EVENT);
|
||||
return;
|
||||
}
|
||||
if (recruitcost > 0) {
|
||||
int pooled =
|
||||
get_pooled(u, get_resourcetype(R_SILVER), GET_DEFAULT, recruitcost * n);
|
||||
int pr = pooled / recruitcost;
|
||||
if (n > pr) n = pr;
|
||||
}
|
||||
|
||||
u->wants = n;
|
||||
|
||||
if (!n) {
|
||||
cmistake(u, ord, 142, MSG_EVENT);
|
||||
return;
|
||||
}
|
||||
if (has_skill(u, SK_ALCHEMY)) {
|
||||
if (count_skill(u->faction, SK_ALCHEMY) + n > skill_limit(u->faction, SK_ALCHEMY)) {
|
||||
cmistake(u, ord, 156, MSG_EVENT);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
assert(rc);
|
||||
msg = can_recruit(u, rc, ord, turn);
|
||||
if (msg) {
|
||||
add_message(&u->faction->msgs, msg);
|
||||
msg_release(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
u_setrace(u, rc);
|
||||
u->wants = n;
|
||||
o = (econ_request *)calloc(1, sizeof(econ_request));
|
||||
o->qty = n;
|
||||
o->unit = u;
|
||||
|
@ -1252,7 +1258,6 @@ static void create_potion(unit * u, const item_type * itype, int want)
|
|||
/* something missing from the list of materials */
|
||||
ADDMSG(&u->faction->msgs, msg_materials_required(u, u->thisorder,
|
||||
itype->construction, want));
|
||||
return;
|
||||
break;
|
||||
default:
|
||||
i_change(&u->items, itype, built);
|
||||
|
@ -1661,7 +1666,7 @@ static void buy(unit * u, econ_request ** buyorders, struct order *ord)
|
|||
return;
|
||||
}
|
||||
}
|
||||
if (r_demand(r, ltype)) {
|
||||
if (!r->land || r_demand(r, ltype)) {
|
||||
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "luxury_notsold", ""));
|
||||
return;
|
||||
}
|
||||
|
@ -1703,6 +1708,7 @@ static void expandselling(region * r, econ_request * sellorders, int limit)
|
|||
static int bt_cache;
|
||||
static const struct building_type *castle_bt, *harbour_bt, *caravan_bt;
|
||||
|
||||
assert(r->land);
|
||||
if (bt_changed(&bt_cache)) {
|
||||
castle_bt = bt_find("castle");
|
||||
harbour_bt = bt_find("harbour");
|
||||
|
@ -1972,7 +1978,7 @@ static bool sell(unit * u, econ_request ** sellorders, struct order *ord)
|
|||
econ_request *o;
|
||||
int k, available;
|
||||
|
||||
if (!r_demand(r, ltype)) {
|
||||
if (!r->land || !r_demand(r, ltype)) {
|
||||
cmistake(u, ord, 263, MSG_COMMERCE);
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@ extern "C" {
|
|||
#define MAXNEWBIES 5
|
||||
|
||||
struct unit;
|
||||
struct race;
|
||||
struct region;
|
||||
struct faction;
|
||||
struct order;
|
||||
|
@ -94,6 +95,7 @@ extern "C" {
|
|||
void steal_cmd(struct unit * u, struct order *ord, struct econ_request ** stealorders);
|
||||
void expandstealing(struct region * r, struct econ_request * stealorders);
|
||||
|
||||
struct message *can_recruit(struct unit *u, const struct race *rc, struct order *ord, int now);
|
||||
void add_recruits(struct unit * u, int number, int wanted);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -145,6 +145,7 @@ static struct unit *create_recruiter(void) {
|
|||
|
||||
static void setup_production(void) {
|
||||
init_resources();
|
||||
mt_create_feedback("error_cannotmake");
|
||||
mt_create_va(mt_new("produce", NULL), "unit:unit", "region:region", "amount:int", "wanted:int", "resource:resource", MT_NEW_END);
|
||||
mt_create_va(mt_new("income", NULL), "unit:unit", "region:region", "amount:int", "wanted:int", "mode:int", MT_NEW_END);
|
||||
mt_create_va(mt_new("buy", NULL), "unit:unit", "money:int", MT_NEW_END);
|
||||
|
@ -480,6 +481,35 @@ static void test_recruit(CuTest *tc) {
|
|||
test_teardown();
|
||||
}
|
||||
|
||||
static void test_recruit_insect(CuTest *tc) {
|
||||
unit *u;
|
||||
faction *f;
|
||||
message * msg;
|
||||
|
||||
test_setup();
|
||||
test_create_calendar();
|
||||
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);
|
||||
|
||||
msg = can_recruit(u, f->race, u->thisorder, 1083); /* Autumn */
|
||||
CuAssertPtrEquals(tc, NULL, msg);
|
||||
|
||||
msg = can_recruit(u, f->race, u->thisorder, 1084); /* Insects, Winter */
|
||||
CuAssertPtrNotNull(tc, msg);
|
||||
msg_release(msg);
|
||||
|
||||
u->flags |= UFL_WARMTH;
|
||||
msg = can_recruit(u, f->race, u->thisorder, 1084); /* Insects, potion, Winter */
|
||||
CuAssertPtrEquals(tc, NULL, msg);
|
||||
|
||||
u->flags = 0;
|
||||
msg = can_recruit(u, NULL, u->thisorder, 1084); /* Other races, Winter */
|
||||
CuAssertPtrEquals(tc, NULL, msg);
|
||||
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
static void test_income(CuTest *tc)
|
||||
{
|
||||
race *rc;
|
||||
|
@ -708,6 +738,7 @@ static void test_loot(CuTest *tc) {
|
|||
|
||||
test_setup();
|
||||
setup_production();
|
||||
mt_create_error(48); /* unit is unarmed */
|
||||
it_silver = test_create_silver();
|
||||
config_set("rules.enable_loot", "1");
|
||||
u = test_create_unit(f = test_create_faction(NULL), test_create_region(0, 0, NULL));
|
||||
|
@ -717,7 +748,7 @@ static void test_loot(CuTest *tc) {
|
|||
test_clear_messages(f);
|
||||
arm_unit(u);
|
||||
produce(u->region);
|
||||
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "income")); /* unit is unarmed */
|
||||
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "income"));
|
||||
CuAssertIntEquals(tc, 2 * TAXFRACTION, i_get(u->items, it_silver));
|
||||
CuAssertIntEquals(tc, UFL_LONGACTION | UFL_NOTMOVING, fval(u, UFL_LONGACTION | UFL_NOTMOVING));
|
||||
test_teardown();
|
||||
|
@ -764,6 +795,7 @@ CuSuite *get_economy_suite(void)
|
|||
SUITE_ADD_TEST(suite, test_trade_insect);
|
||||
SUITE_ADD_TEST(suite, test_maintain_buildings);
|
||||
SUITE_ADD_TEST(suite, test_recruit);
|
||||
SUITE_ADD_TEST(suite, test_recruit_insect);
|
||||
SUITE_ADD_TEST(suite, test_loot);
|
||||
SUITE_ADD_TEST(suite, test_expand_production);
|
||||
return suite;
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
#include "attributes/attributes.h"
|
||||
#include "races/races.h"
|
||||
|
||||
#include "chaos.h"
|
||||
#include "items.h"
|
||||
#include "creport.h"
|
||||
#include "report.h"
|
||||
|
@ -82,5 +81,4 @@ void game_init(void)
|
|||
register_attributes();
|
||||
register_gmcmd();
|
||||
|
||||
chaos_register();
|
||||
}
|
||||
|
|
443
src/exparse.c
443
src/exparse.c
File diff suppressed because it is too large
Load diff
|
@ -65,11 +65,14 @@ static void setup_give(struct give *env) {
|
|||
mt_create_va(mt_new("give", NULL), "unit:unit", "target:unit", "resource:resource", "amount:int", MT_NEW_END);
|
||||
mt_create_va(mt_new("give_peasants", NULL), "unit:unit", "resource:resource", "amount:int", MT_NEW_END);
|
||||
/* error messages: */
|
||||
mt_create_error(129);
|
||||
mt_create_error(96);
|
||||
mt_create_error(10);
|
||||
mt_create_feedback("feedback_give_forbidden");
|
||||
mt_create_feedback("peasants_give_invalid");
|
||||
mt_create_va(mt_new("too_many_units_in_faction", NULL), "unit:unit", "region:region", "command:order", "allowed:int", MT_NEW_END);
|
||||
mt_create_va(mt_new("too_many_units_in_alliance", NULL), "unit:unit", "region:region", "command:order", "allowed:int", MT_NEW_END);
|
||||
mt_create_va(mt_new("feedback_no_contact", NULL), "unit:unit", "region:region", "command:order", "target:unit", MT_NEW_END);
|
||||
mt_create_va(mt_new("feedback_give_forbidden", NULL), "unit:unit", "region:region", "command:order", MT_NEW_END);
|
||||
mt_create_va(mt_new("peasants_give_invalid", NULL), "unit:unit", "region:region", "command:order", MT_NEW_END);
|
||||
mt_create_va(mt_new("giverestriction", NULL), "unit:unit", "region:region", "command:order", "turns:int", MT_NEW_END);
|
||||
mt_create_va(mt_new("error_unit_size", NULL), "unit:unit", "region:region", "command:order", "maxsize:int", MT_NEW_END);
|
||||
mt_create_va(mt_new("nogive_reserved", NULL), "unit:unit", "region:region", "command:order", "resource:resource", "reservation:int", MT_NEW_END);
|
||||
|
@ -91,7 +94,7 @@ static void test_give_unit(CuTest * tc) {
|
|||
give_unit(env.src, env.dst, NULL);
|
||||
CuAssertPtrEquals(tc, env.f2, env.src->faction);
|
||||
CuAssertIntEquals(tc, 1, env.f2->newbies);
|
||||
CuAssertPtrEquals(tc, 0, env.f1->units);
|
||||
CuAssertPtrEquals(tc, NULL, env.f1->units);
|
||||
CuAssertPtrNotNull(tc, test_find_messagetype(env.f1->msgs, "give_person"));
|
||||
CuAssertPtrNotNull(tc, test_find_messagetype(env.f2->msgs, "receive_person"));
|
||||
test_teardown();
|
||||
|
@ -159,11 +162,12 @@ static void test_give_men_magicians(CuTest * tc) {
|
|||
message * msg;
|
||||
|
||||
test_setup_ex(tc);
|
||||
mt_create_error(158);
|
||||
env.f2 = env.f1 = test_create_faction(NULL);
|
||||
setup_give(&env);
|
||||
set_level(env.src, SK_MAGIC, 1);
|
||||
CuAssertPtrNotNull(tc, msg = give_men(1, env.src, env.dst, NULL));
|
||||
CuAssertStrEquals(tc, "error158", (const char *)msg->parameters[3].v);
|
||||
CuAssertStrEquals(tc, "error158", test_get_messagetype(msg));
|
||||
CuAssertIntEquals(tc, 1, env.dst->number);
|
||||
CuAssertIntEquals(tc, 1, env.src->number);
|
||||
msg_release(msg);
|
||||
|
@ -303,7 +307,7 @@ static void test_give_men_requires_contact(CuTest * tc) {
|
|||
ord = create_order(K_GIVE, env.f1->locale, "%s ALLES PERSONEN", itoa36(env.dst->no));
|
||||
test_clear_messages(env.f1);
|
||||
give_cmd(env.src, ord);
|
||||
CuAssertPtrEquals(tc, 0, test_find_messagetype(env.f1->msgs, "give_person"));
|
||||
CuAssertPtrEquals(tc, NULL, test_find_messagetype(env.f1->msgs, "give_person"));
|
||||
CuAssertPtrNotNull(tc, test_find_messagetype(env.f1->msgs, "feedback_no_contact"));
|
||||
|
||||
msg_release(msg);
|
||||
|
@ -407,7 +411,7 @@ static void test_give_okay(CuTest * tc) {
|
|||
setup_give(&env);
|
||||
|
||||
config_set("rules.give.flags", "0");
|
||||
CuAssertPtrEquals(tc, 0, check_give(env.src, env.dst, NULL));
|
||||
CuAssertPtrEquals(tc, NULL, check_give(env.src, env.dst, NULL));
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
|
@ -450,7 +454,7 @@ static void test_give_new_unit(CuTest * tc) {
|
|||
setup_give(&env);
|
||||
env.dst->number = 0;
|
||||
fset(env.dst, UFL_ISNEW);
|
||||
CuAssertPtrEquals(tc, 0, check_give(env.src, env.dst, NULL));
|
||||
CuAssertPtrEquals(tc, NULL, check_give(env.src, env.dst, NULL));
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
|
|
184
src/gmtool.c
184
src/gmtool.c
|
@ -46,16 +46,17 @@
|
|||
#include <util/log.h>
|
||||
#include <util/macros.h>
|
||||
#include <util/path.h>
|
||||
#include <util/rand.h>
|
||||
#include <util/rng.h>
|
||||
#include <util/unicode.h>
|
||||
|
||||
#include "gmtool_structs.h"
|
||||
#include "chaos.h"
|
||||
#include "console.h"
|
||||
#include "listbox.h"
|
||||
#include "wormhole.h"
|
||||
#include "teleport.h"
|
||||
|
||||
#include <selist.h>
|
||||
#include <storage.h>
|
||||
#include <lua.h>
|
||||
|
||||
|
@ -452,7 +453,10 @@ static void paint_info_region(window * wnd, const state * st)
|
|||
line++;
|
||||
umvwprintw(win, line++, 1, "%s, age %d", r->terrain->_name, r->age);
|
||||
if (r->land) {
|
||||
int iron = region_getresource_level(r, get_resourcetype(R_IRON));
|
||||
int stone = region_getresource_level(r, get_resourcetype(R_STONE));
|
||||
mvwprintw(win, line++, 1, "$:%6d P:%5d", rmoney(r), rpeasants(r));
|
||||
mvwprintw(win, line++, 1, "S:%6d I:%5d", stone, iron);
|
||||
mvwprintw(win, line++, 1, "H:%6d %s:%5d", rhorses(r),
|
||||
(r->flags & RF_MALLORN) ? "M" : "T",
|
||||
r->land->trees[1] + r->land->trees[2]);
|
||||
|
@ -530,18 +534,60 @@ static void statusline(WINDOW * win, const char *str)
|
|||
wnoutrefresh(win);
|
||||
}
|
||||
|
||||
static void reset_resources(region *r, const struct terrain_type *terrain)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; terrain->production[i].type; ++i) {
|
||||
rawmaterial *rm;
|
||||
const terrain_production *production = terrain->production + i;
|
||||
const resource_type *rtype = production->type;
|
||||
|
||||
for (rm = r->resources; rm; rm = rm->next) {
|
||||
if (rm->rtype == rtype)
|
||||
break;
|
||||
}
|
||||
if (rm) {
|
||||
struct rawmaterial_type *rmt;
|
||||
set_resource(rm,
|
||||
dice_rand(production->startlevel),
|
||||
dice_rand(production->base),
|
||||
dice_rand(production->divisor));
|
||||
rmt = rmt_get(rtype);
|
||||
if (rmt && rmt->terraform) {
|
||||
rmt->terraform(rm, r);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void reset_region(region *r) {
|
||||
set_chaoscount(r, 0);
|
||||
unit **up = &r->units;
|
||||
bool players = false;
|
||||
|
||||
r->flags = 0;
|
||||
a_removeall(&r->attribs, NULL);
|
||||
while (r->units) {
|
||||
remove_unit(&r->units, r->units);
|
||||
while (*up) {
|
||||
unit *u = *up;
|
||||
if (is_monsters(u->faction)) {
|
||||
remove_unit(up, u);
|
||||
}
|
||||
else {
|
||||
players = true;
|
||||
up = &u->next;
|
||||
}
|
||||
}
|
||||
while (r->ships) {
|
||||
remove_ship(&r->ships, r->ships);
|
||||
}
|
||||
while (r->buildings) {
|
||||
remove_building(&r->buildings, r->buildings);
|
||||
if (!players) {
|
||||
while (r->ships) {
|
||||
remove_ship(&r->ships, r->ships);
|
||||
}
|
||||
while (r->buildings) {
|
||||
remove_building(&r->buildings, r->buildings);
|
||||
}
|
||||
if (r->land) {
|
||||
init_region(r);
|
||||
reset_resources(r, r->terrain);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -586,6 +632,69 @@ static void terraform_at(coordinate * c, const terrain_type * terrain)
|
|||
}
|
||||
}
|
||||
|
||||
static void selection_walk(selection * selected, void(*callback)(region *, void *), void *udata) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i != MAXTHASH; ++i) {
|
||||
tag **tp = &selected->tags[i];
|
||||
while (*tp) {
|
||||
region *r;
|
||||
tag *t = *tp;
|
||||
int nx = t->coord.x, ny = t->coord.y;
|
||||
plane *pl = t->coord.pl;
|
||||
|
||||
pnormalize(&nx, &ny, pl);
|
||||
r = findregion(nx, ny);
|
||||
if (r != NULL) {
|
||||
callback(r, udata);
|
||||
}
|
||||
tp = &t->nexthash;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void reset_levels_cb(region *r, void *udata) {
|
||||
struct rawmaterial *res;
|
||||
UNUSED_ARG(udata);
|
||||
for (res = r->resources; res; res = res->next) {
|
||||
if (res->level > 3) {
|
||||
res->level = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* BUG 2506: reset drained mountains to level 1
|
||||
*/
|
||||
static void
|
||||
fix_selection(selection * selected)
|
||||
{
|
||||
selection_walk(selected, reset_levels_cb, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
reset_selection(selection * selected)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i != MAXTHASH; ++i) {
|
||||
tag **tp = &selected->tags[i];
|
||||
while (*tp) {
|
||||
region *r;
|
||||
tag *t = *tp;
|
||||
int nx = t->coord.x, ny = t->coord.y;
|
||||
plane *pl = t->coord.pl;
|
||||
|
||||
pnormalize(&nx, &ny, pl);
|
||||
r = findregion(nx, ny);
|
||||
if (r != NULL) {
|
||||
reset_region(r);
|
||||
}
|
||||
tp = &t->nexthash;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
terraform_selection(selection * selected, const terrain_type * terrain)
|
||||
{
|
||||
|
@ -695,7 +804,7 @@ void highlight_region(region * r, int toggle)
|
|||
}
|
||||
}
|
||||
|
||||
void select_coordinate(struct selection *selected, int nx, int ny, int toggle)
|
||||
void select_coordinate(struct selection *selected, int nx, int ny, bool toggle)
|
||||
{
|
||||
if (toggle)
|
||||
tag_region(selected, nx, ny);
|
||||
|
@ -703,7 +812,50 @@ void select_coordinate(struct selection *selected, int nx, int ny, int toggle)
|
|||
untag_region(selected, nx, ny);
|
||||
}
|
||||
|
||||
enum { MODE_MARK, MODE_SELECT, MODE_UNMARK, MODE_UNSELECT };
|
||||
enum select_t { MODE_MARK, MODE_SELECT, MODE_UNMARK, MODE_UNSELECT };
|
||||
|
||||
static void select_island(state *st, int selectmode)
|
||||
{
|
||||
region *r;
|
||||
int nx = st->cursor.x;
|
||||
int ny = st->cursor.y;
|
||||
|
||||
pnormalize(&nx, &ny, st->cursor.pl);
|
||||
r = findregion(nx, ny);
|
||||
if (r && r->land) {
|
||||
selist *ql, *stack = NULL;
|
||||
int qi = 0;
|
||||
|
||||
selist_push(&stack, r);
|
||||
for (ql = stack, qi = 0; ql; selist_advance(&ql, &qi, 1)) {
|
||||
region *r = (region *)selist_get(ql, qi);
|
||||
region *rnext[MAXDIRECTIONS];
|
||||
int i;
|
||||
|
||||
fset(r, RF_MARK);
|
||||
if (selectmode & MODE_SELECT) {
|
||||
select_coordinate(st->selected, r->x, r->y,
|
||||
selectmode == MODE_SELECT);
|
||||
}
|
||||
else {
|
||||
highlight_region(r, selectmode == MODE_MARK);
|
||||
}
|
||||
get_neighbours(r, rnext);
|
||||
for (i = 0; i != MAXDIRECTIONS; ++i) {
|
||||
region *rn = rnext[i];
|
||||
if (rn && rn->land && !fval(rn, RF_MARK)) {
|
||||
selist_push(&stack, rn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (ql = stack, qi = 0; ql; selist_advance(&ql, &qi, 1)) {
|
||||
region *r = (region *)selist_get(ql, qi);
|
||||
freset(r, RF_MARK);
|
||||
}
|
||||
selist_free(stack);
|
||||
}
|
||||
}
|
||||
|
||||
static void select_regions(state * st, int selectmode)
|
||||
{
|
||||
|
@ -857,6 +1009,11 @@ static void select_regions(state * st, int selectmode)
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (findmode == 'i') {
|
||||
sprintf(sbuffer, "%swand: ", status);
|
||||
statusline(st->wnd_status->handle, sbuffer);
|
||||
select_island(st, selectmode);
|
||||
}
|
||||
else if (findmode == 't') {
|
||||
const struct terrain_type *terrain;
|
||||
sprintf(sbuffer, "%sterrain: ", status);
|
||||
|
@ -1197,7 +1354,12 @@ static void handlekey(state * st, int c)
|
|||
statusline(st->wnd_status->handle, "tag-");
|
||||
doupdate();
|
||||
switch (getch()) {
|
||||
case 'r':
|
||||
reset_selection(st->selected);
|
||||
break;
|
||||
case 'f':
|
||||
fix_selection(st->selected);
|
||||
break;
|
||||
case 't':
|
||||
terraform_selection(st->selected, select_terrain(st, NULL));
|
||||
st->modified = 1;
|
||||
|
|
|
@ -29,7 +29,7 @@ extern "C" {
|
|||
const char *prompt);
|
||||
|
||||
void highlight_region(struct region *r, int on);
|
||||
void select_coordinate(struct selection *selected, int x, int y, int on);
|
||||
void select_coordinate(struct selection *selected, int x, int y, bool on);
|
||||
void run_mapper(void);
|
||||
|
||||
extern int force_color;
|
||||
|
|
|
@ -18,7 +18,6 @@ static void test_manacrystal(CuTest *tc) {
|
|||
unit *u;
|
||||
|
||||
test_setup();
|
||||
test_inject_messagetypes();
|
||||
|
||||
u = test_create_unit(test_create_faction(NULL), test_create_plain(0, 0));
|
||||
itype = test_create_itemtype("manacrystal");
|
||||
|
@ -49,7 +48,6 @@ static void test_skillpotion(CuTest *tc) {
|
|||
int initialWeeks_Magic = 0;
|
||||
|
||||
test_setup();
|
||||
test_inject_messagetypes();
|
||||
u = test_create_unit(test_create_faction(NULL), test_create_plain(0, 0));
|
||||
itype = test_create_itemtype("skillpotion");
|
||||
change_resource(u, itype->rtype, 2);
|
||||
|
|
|
@ -500,50 +500,46 @@ static int count_materials(unit *u, const construction *type, int n, int complet
|
|||
return n;
|
||||
}
|
||||
|
||||
int build_skill(unit *u, int basesk, int skill_mod) {
|
||||
int effsk, skills;
|
||||
int dm = get_effect(u, oldpotiontype[P_DOMORE]);
|
||||
|
||||
effsk = basesk + skill_mod;
|
||||
assert(effsk >= 0);
|
||||
|
||||
skills = effsk * u->number;
|
||||
|
||||
/* technically, nimblefinge and domore should be in a global set of
|
||||
* "game"-attributes, (as at_skillmod) but for a while, we're leaving
|
||||
* them in here. */
|
||||
|
||||
if (dm != 0) {
|
||||
/* Auswirkung Schaffenstrunk */
|
||||
if (dm > u->number) dm = u->number;
|
||||
change_effect(u, oldpotiontype[P_DOMORE], -dm);
|
||||
skills += dm * effsk;
|
||||
}
|
||||
return skills;
|
||||
}
|
||||
|
||||
/** Use up resources for building an object.
|
||||
* Build up to 'size' points of 'type', where 'completed'
|
||||
* of the first object have already been finished. return the
|
||||
* actual size that could be built.
|
||||
*/
|
||||
int build(unit * u, const construction * ctype, int completed, int want, int skill_mod)
|
||||
{
|
||||
const construction *con = ctype;
|
||||
int skills = INT_MAX; /* number of skill points remainig */
|
||||
int basesk = 0;
|
||||
static int build_limited(unit * u, const construction * con, int completed, int want, int basesk, int *skill_total) {
|
||||
int skills = *skill_total;
|
||||
int made = 0;
|
||||
|
||||
if (want <= 0)
|
||||
if (want <= 0) {
|
||||
return 0;
|
||||
}
|
||||
if (con == NULL) {
|
||||
return ENOMATERIALS;
|
||||
}
|
||||
if (completed == con->maxsize) {
|
||||
return ECOMPLETE;
|
||||
}
|
||||
if (con->skill != NOSKILL) {
|
||||
int effsk;
|
||||
int dm = get_effect(u, oldpotiontype[P_DOMORE]);
|
||||
|
||||
basesk = effskill(u, con->skill, 0);
|
||||
if (basesk == 0)
|
||||
return ENEEDSKILL;
|
||||
|
||||
effsk = basesk + skill_mod;
|
||||
assert(effsk >= 0);
|
||||
|
||||
skills = effsk * u->number;
|
||||
|
||||
/* technically, nimblefinge and domore should be in a global set of
|
||||
* "game"-attributes, (as at_skillmod) but for a while, we're leaving
|
||||
* them in here. */
|
||||
|
||||
if (dm != 0) {
|
||||
/* Auswirkung Schaffenstrunk */
|
||||
if (dm > u->number) dm = u->number;
|
||||
change_effect(u, oldpotiontype[P_DOMORE], -dm);
|
||||
skills += dm * effsk;
|
||||
}
|
||||
}
|
||||
for (; want > 0 && skills > 0;) {
|
||||
int err, n;
|
||||
|
||||
|
@ -610,9 +606,27 @@ int build(unit * u, const construction * ctype, int completed, int want, int ski
|
|||
want -= n;
|
||||
completed = completed + n;
|
||||
}
|
||||
/* Nur soviel PRODUCEEXP wie auch tatsaechlich gemacht wurde */
|
||||
produceexp(u, ctype->skill, (made < u->number) ? made : u->number);
|
||||
*skill_total = skills;
|
||||
return made;
|
||||
}
|
||||
|
||||
int build(unit * u, const construction * con, int completed, int want, int skill_mod)
|
||||
{
|
||||
int skills = INT_MAX; /* number of skill points remainig */
|
||||
int made, basesk = 0;
|
||||
|
||||
assert(con->skill != NOSKILL);
|
||||
basesk = effskill(u, con->skill, 0);
|
||||
if (basesk == 0) {
|
||||
return ENEEDSKILL;
|
||||
}
|
||||
|
||||
skills = build_skill(u, basesk, skill_mod);
|
||||
made = build_limited(u, con, completed, want, basesk, &skills);
|
||||
/* Nur soviel PRODUCEEXP wie auch tatsaechlich gemacht wurde */
|
||||
if (made > 0) {
|
||||
produceexp(u, con->skill, (made < u->number) ? made : u->number);
|
||||
}
|
||||
return made;
|
||||
}
|
||||
|
||||
|
@ -681,7 +695,7 @@ static int build_failure(unit *u, order *ord, const building_type *btype, int wa
|
|||
return err;
|
||||
}
|
||||
|
||||
static int build_stages(unit *u, const building_type *btype, int built, int n) {
|
||||
static int build_stages(unit *u, const building_type *btype, int built, int n, int basesk, int *skill_total) {
|
||||
|
||||
const building_stage *stage;
|
||||
int made = 0;
|
||||
|
@ -701,7 +715,7 @@ static int build_stages(unit *u, const building_type *btype, int built, int n) {
|
|||
want = todo;
|
||||
}
|
||||
}
|
||||
err = build(u, con, built, want, 0);
|
||||
err = build_limited(u, con, built, want, basesk, skill_total);
|
||||
if (err < 0) {
|
||||
if (made == 0) {
|
||||
/* could not make any part at all */
|
||||
|
@ -739,10 +753,14 @@ build_building(unit * u, const building_type * btype, int id, int want, order *
|
|||
const char *btname;
|
||||
order *new_order = NULL;
|
||||
const struct locale *lang = u->faction->locale;
|
||||
int skills, basesk; /* number of skill points remainig */
|
||||
|
||||
assert(u->number);
|
||||
assert(btype->stages && btype->stages->construction);
|
||||
if (effskill(u, SK_BUILDING, 0) == 0) {
|
||||
|
||||
basesk = effskill(u, SK_BUILDING, 0);
|
||||
skills = build_skill(u, basesk, 0);
|
||||
if (skills == 0) {
|
||||
cmistake(u, ord, 101, MSG_PRODUCE);
|
||||
return 0;
|
||||
}
|
||||
|
@ -832,7 +850,7 @@ build_building(unit * u, const building_type * btype, int id, int want, order *
|
|||
}
|
||||
}
|
||||
|
||||
built = build_stages(u, btype, built, n);
|
||||
built = build_stages(u, btype, built, n, basesk, &skills);
|
||||
|
||||
if (built < 0) {
|
||||
return build_failure(u, ord, btype, want, built);
|
||||
|
@ -895,7 +913,9 @@ build_building(unit * u, const building_type * btype, int id, int want, order *
|
|||
}
|
||||
fset(b, BLD_EXPANDED);
|
||||
|
||||
update_lighthouse(b);
|
||||
if (is_lighthouse(btype)) {
|
||||
update_lighthouse(b);
|
||||
}
|
||||
|
||||
return built;
|
||||
}
|
||||
|
|
|
@ -17,8 +17,9 @@
|
|||
#include <CuTest.h>
|
||||
#include <tests.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
|
||||
typedef struct build_fixture {
|
||||
faction *f;
|
||||
|
@ -31,7 +32,6 @@ typedef struct build_fixture {
|
|||
|
||||
static unit * setup_build(build_fixture *bf) {
|
||||
test_setup();
|
||||
test_inject_messagetypes();
|
||||
init_resources();
|
||||
|
||||
test_create_itemtype("stone");
|
||||
|
@ -53,6 +53,53 @@ static unit * setup_build(build_fixture *bf) {
|
|||
return bf->u;
|
||||
}
|
||||
|
||||
static building_type *setup_castle(item_type *it_stone) {
|
||||
building_type *btype;
|
||||
building_stage *stage;
|
||||
construction * cons;
|
||||
|
||||
btype = test_create_buildingtype("castle");
|
||||
stage = btype->stages = calloc(1, sizeof(building_stage));
|
||||
cons = stage->construction = calloc(1, sizeof(construction));
|
||||
cons->materials = calloc(2, sizeof(requirement));
|
||||
cons->materials[0].number = 1;
|
||||
cons->materials[0].rtype = it_stone->rtype;
|
||||
cons->minskill = 1;
|
||||
cons->maxsize = 2;
|
||||
cons->reqsize = 1;
|
||||
cons->skill = SK_BUILDING;
|
||||
stage = stage->next = calloc(1, sizeof(building_stage));
|
||||
cons = stage->construction = calloc(1, sizeof(construction));
|
||||
cons->materials = calloc(2, sizeof(requirement));
|
||||
cons->materials[0].number = 1;
|
||||
cons->materials[0].rtype = it_stone->rtype;
|
||||
cons->minskill = 1;
|
||||
cons->maxsize = 8;
|
||||
cons->reqsize = 1;
|
||||
cons->skill = SK_BUILDING;
|
||||
return btype;
|
||||
}
|
||||
|
||||
static void test_build_building_stages(CuTest *tc) {
|
||||
building_type *btype;
|
||||
item_type *it_stone;
|
||||
unit *u;
|
||||
|
||||
test_setup();
|
||||
init_resources();
|
||||
it_stone = test_create_itemtype("stone");
|
||||
btype = setup_castle(it_stone);
|
||||
u = test_create_unit(test_create_faction(NULL), test_create_plain(0, 0));
|
||||
set_level(u, SK_BUILDING, 2);
|
||||
i_change(&u->items, it_stone, 4);
|
||||
build_building(u, btype, -1, INT_MAX, NULL);
|
||||
CuAssertPtrNotNull(tc, u->building);
|
||||
CuAssertIntEquals(tc, 2, u->building->size);
|
||||
CuAssertIntEquals(tc, 2, i_get(u->items, it_stone));
|
||||
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
static void teardown_build(build_fixture *bf) {
|
||||
free(bf->cons.materials);
|
||||
test_teardown();
|
||||
|
@ -307,7 +354,6 @@ static void test_build_destroy_road_guard(CuTest *tc)
|
|||
order *ord;
|
||||
|
||||
test_setup();
|
||||
test_inject_messagetypes();
|
||||
test_create_region(1, 0, 0);
|
||||
r = test_create_region(0, 0, NULL);
|
||||
rsetroad(r, D_EAST, 100);
|
||||
|
@ -340,7 +386,6 @@ static void test_build_destroy_road_limit(CuTest *tc)
|
|||
order *ord;
|
||||
|
||||
test_setup();
|
||||
test_inject_messagetypes();
|
||||
test_create_region(1, 0, 0);
|
||||
r = test_create_region(0, 0, NULL);
|
||||
rsetroad(r, D_EAST, 100);
|
||||
|
@ -365,6 +410,7 @@ static void test_build_destroy_cmd(CuTest *tc) {
|
|||
faction *f;
|
||||
|
||||
test_setup();
|
||||
mt_create_error(138);
|
||||
u = test_create_unit(f = test_create_faction(NULL), test_create_region(0, 0, NULL));
|
||||
u->thisorder = create_order(K_DESTROY, f->locale, NULL);
|
||||
CuAssertIntEquals(tc, 138, destroy_cmd(u, u->thisorder));
|
||||
|
@ -392,6 +438,7 @@ CuSuite *get_build_suite(void)
|
|||
SUITE_ADD_TEST(suite, test_build_with_ring);
|
||||
SUITE_ADD_TEST(suite, test_build_with_potion);
|
||||
SUITE_ADD_TEST(suite, test_build_building_success);
|
||||
SUITE_ADD_TEST(suite, test_build_building_stages);
|
||||
SUITE_ADD_TEST(suite, test_build_building_with_golem);
|
||||
SUITE_ADD_TEST(suite, test_build_building_no_materials);
|
||||
SUITE_ADD_TEST(suite, test_build_destroy_cmd);
|
||||
|
|
|
@ -377,7 +377,9 @@ building *new_building(const struct building_type * btype, region * r,
|
|||
bptr = &(*bptr)->next;
|
||||
*bptr = b;
|
||||
|
||||
update_lighthouse(b);
|
||||
if (is_lighthouse(b->type)) {
|
||||
update_lighthouse(b);
|
||||
}
|
||||
bname = LOC(lang, btype->_name);
|
||||
if (!bname) {
|
||||
bname = LOC(lang, parameters[P_GEBAEUDE]);
|
||||
|
@ -399,6 +401,7 @@ static building *deleted_buildings;
|
|||
void remove_building(building ** blist, building * b)
|
||||
{
|
||||
unit *u;
|
||||
region *r = b->region;
|
||||
static const struct building_type *bt_caravan, *bt_dam, *bt_tunnel;
|
||||
static int btypes;
|
||||
|
||||
|
@ -410,18 +413,19 @@ void remove_building(building ** blist, building * b)
|
|||
bt_tunnel = bt_find("tunnel");
|
||||
}
|
||||
handle_event(b->attribs, "destroy", b);
|
||||
for (u = b->region->units; u; u = u->next) {
|
||||
for (u = r->units; u; u = u->next) {
|
||||
if (u->building == b) leave(u, true);
|
||||
}
|
||||
|
||||
if (is_lighthouse(b->type)) {
|
||||
remove_lighthouse(b);
|
||||
}
|
||||
b->size = 0;
|
||||
update_lighthouse(b);
|
||||
bunhash(b);
|
||||
|
||||
/* Falls Karawanserei, Damm oder Tunnel einst<73>rzen, wird die schon
|
||||
* gebaute Strasse zur Haelfte vernichtet */
|
||||
if (b->type == bt_caravan || b->type == bt_dam || b->type == bt_tunnel) {
|
||||
region *r = b->region;
|
||||
int d;
|
||||
for (d = 0; d != MAXDIRECTIONS; ++d) {
|
||||
direction_t dir = (direction_t)d;
|
||||
|
|
|
@ -135,7 +135,8 @@ const char *parameters[MAXPARAMS] = {
|
|||
"GRUPPE",
|
||||
"PARTEITARNUNG",
|
||||
"BAEUME",
|
||||
"ALLIANZ"
|
||||
"ALLIANZ",
|
||||
"AUTO"
|
||||
};
|
||||
|
||||
int findoption(const char *s, const struct locale *lang)
|
||||
|
@ -631,28 +632,24 @@ void kernel_init(void)
|
|||
translation_init();
|
||||
}
|
||||
|
||||
static order * defaults[MAXLOCALES];
|
||||
|
||||
order *default_order(const struct locale *lang)
|
||||
{
|
||||
int i = locale_index(lang);
|
||||
keyword_t kwd;
|
||||
const char * str;
|
||||
order *result = 0;
|
||||
assert(i < MAXLOCALES);
|
||||
|
||||
result = defaults[i];
|
||||
if (!result) {
|
||||
const char * str;
|
||||
keyword_t kwd = NOKEYWORD;
|
||||
str = config_get("orders.default");
|
||||
if (str) {
|
||||
kwd = findkeyword(str);
|
||||
}
|
||||
if (kwd != NOKEYWORD) {
|
||||
result = create_order(kwd, lang, NULL);
|
||||
defaults[i] = result;
|
||||
}
|
||||
assert(i < MAXLOCALES);
|
||||
kwd = keyword_disabled(K_WORK) ? NOKEYWORD : K_WORK;
|
||||
str = config_get("orders.default");
|
||||
if (str) {
|
||||
kwd = findkeyword(str);
|
||||
}
|
||||
return result ? copy_order(result) : 0;
|
||||
if (kwd != NOKEYWORD) {
|
||||
result = create_order(kwd, lang, NULL);
|
||||
return copy_order(result);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int rule_give(void)
|
||||
|
@ -760,14 +757,6 @@ void free_config(void) {
|
|||
*/
|
||||
void free_gamedata(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i != MAXLOCALES; ++i) {
|
||||
if (defaults[i]) {
|
||||
free_order(defaults[i]);
|
||||
defaults[i] = 0;
|
||||
}
|
||||
}
|
||||
free(forbidden_ids);
|
||||
forbidden_ids = NULL;
|
||||
|
||||
|
|
|
@ -180,15 +180,22 @@ static void test_default_order(CuTest *tc) {
|
|||
|
||||
test_setup();
|
||||
loc = test_create_locale();
|
||||
ord = default_order(loc);
|
||||
CuAssertPtrEquals(tc, 0, ord);
|
||||
free_order(ord);
|
||||
|
||||
config_set("orders.default", "work");
|
||||
ord = default_order(loc);
|
||||
CuAssertPtrNotNull(tc, ord);
|
||||
CuAssertIntEquals(tc, K_WORK, getkeyword(ord));
|
||||
free_order(ord);
|
||||
|
||||
enable_keyword(K_WORK, false);
|
||||
ord = default_order(loc);
|
||||
CuAssertPtrEquals(tc, NULL, ord);
|
||||
free_order(ord);
|
||||
|
||||
config_set("orders.default", "entertain");
|
||||
ord = default_order(loc);
|
||||
CuAssertPtrNotNull(tc, ord);
|
||||
CuAssertIntEquals(tc, K_ENTERTAIN, getkeyword(ord));
|
||||
free_order(ord);
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
|
|
|
@ -51,7 +51,6 @@ typedef struct {
|
|||
|
||||
static void setup_curse(curse_fixture *fix, const char *name) {
|
||||
test_setup();
|
||||
test_inject_messagetypes();
|
||||
fix->r = test_create_region(0, 0, NULL);
|
||||
fix->u = test_create_unit(test_create_faction(NULL), fix->r);
|
||||
fix->c = create_curse(fix->u, &fix->r->attribs, ct_find(name), 1.0, 1, 1.0, 0);
|
||||
|
|
|
@ -29,6 +29,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
#include "group.h"
|
||||
#include "item.h"
|
||||
#include "messages.h"
|
||||
#include "order.h"
|
||||
#include "plane.h"
|
||||
#include "race.h"
|
||||
#include "region.h"
|
||||
|
@ -294,8 +295,13 @@ unit *addplayer(region * r, faction * f)
|
|||
assert(f->units == NULL);
|
||||
faction_setorigin(f, 0, r->x, r->y);
|
||||
u = create_unit(r, f, 1, f->race, 0, NULL, NULL);
|
||||
u->thisorder = default_order(f->locale);
|
||||
unit_addorder(u, copy_order(u->thisorder));
|
||||
name = config_get("rules.equip_first");
|
||||
equip_unit(u, name ? name : "first_unit");
|
||||
if (!equip_unit(u, name ? name : "first_unit")) {
|
||||
/* give every unit enough money to survive the first turn */
|
||||
i_change(&u->items, get_resourcetype(R_SILVER)->itype, maintenance_cost(u));
|
||||
}
|
||||
u->hp = unit_max_hp(u) * u->number;
|
||||
fset(u, UFL_ISNEW);
|
||||
if (f->race == get_race(RC_DAEMON)) {
|
||||
|
@ -486,36 +492,6 @@ void destroyfaction(faction ** fp)
|
|||
}
|
||||
|
||||
handle_event(f->attribs, "destroy", f);
|
||||
#if 0
|
||||
faction *ff;
|
||||
for (ff = factions; ff; ff = ff->next) {
|
||||
group *g;
|
||||
ally *sf, **sfp;
|
||||
|
||||
for (sfp = &ff->allies; *sfp;) {
|
||||
sf = *sfp;
|
||||
if (sf->faction == f || sf->faction == NULL) {
|
||||
*sfp = sf->next;
|
||||
free(sf);
|
||||
}
|
||||
else
|
||||
sfp = &(*sfp)->next;
|
||||
}
|
||||
for (g = ff->groups; g; g = g->next) {
|
||||
for (sfp = &g->allies; *sfp; ) {
|
||||
sf = *sfp;
|
||||
if (sf->faction == f || sf->faction == NULL) {
|
||||
*sfp = sf->next;
|
||||
free(sf);
|
||||
}
|
||||
else {
|
||||
sfp = &(*sfp)->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (f->alliance) {
|
||||
setalliance(f, 0);
|
||||
}
|
||||
|
|
|
@ -3,8 +3,10 @@
|
|||
#include <kernel/ally.h>
|
||||
#include <kernel/alliance.h>
|
||||
#include <kernel/calendar.h>
|
||||
#include <kernel/callbacks.h>
|
||||
#include <kernel/faction.h>
|
||||
#include <kernel/item.h>
|
||||
#include <kernel/order.h>
|
||||
#include <kernel/plane.h>
|
||||
#include <kernel/race.h>
|
||||
#include <kernel/region.h>
|
||||
|
@ -298,9 +300,30 @@ static void test_save_special_items(CuTest *tc) {
|
|||
test_teardown();
|
||||
}
|
||||
|
||||
static void test_addplayer(CuTest *tc) {
|
||||
unit *u;
|
||||
region *r;
|
||||
faction *f;
|
||||
item_type *itype;
|
||||
test_setup();
|
||||
callbacks.equip_unit = NULL;
|
||||
itype = test_create_silver();
|
||||
r = test_create_plain(0, 0);
|
||||
f = test_create_faction(NULL);
|
||||
u = addplayer(r, f);
|
||||
CuAssertPtrNotNull(tc, u);
|
||||
CuAssertPtrEquals(tc, r, u->region);
|
||||
CuAssertPtrEquals(tc, f, u->faction);
|
||||
CuAssertIntEquals(tc, i_get(u->items, itype), 10);
|
||||
CuAssertPtrNotNull(tc, u->orders);
|
||||
CuAssertIntEquals(tc, K_WORK, getkeyword(u->orders));
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
CuSuite *get_faction_suite(void)
|
||||
{
|
||||
CuSuite *suite = CuSuiteNew();
|
||||
SUITE_ADD_TEST(suite, test_addplayer);
|
||||
SUITE_ADD_TEST(suite, test_max_migrants);
|
||||
SUITE_ADD_TEST(suite, test_addfaction);
|
||||
SUITE_ADD_TEST(suite, test_remove_empty_factions);
|
||||
|
|
|
@ -723,7 +723,7 @@ int change_money(unit * u, int v)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int add_resourcename_cb(const void * match, const void * key,
|
||||
static int add_resourcename_cb(void * match, const void * key,
|
||||
size_t keylen, void *data)
|
||||
{
|
||||
struct locale * lang = (struct locale *)data;
|
||||
|
@ -773,7 +773,7 @@ attrib_type at_showitem = {
|
|||
"showitem"
|
||||
};
|
||||
|
||||
static int add_itemname_cb(const void * match, const void * key,
|
||||
static int add_itemname_cb(void * match, const void * key,
|
||||
size_t keylen, void *data)
|
||||
{
|
||||
struct locale * lang = (struct locale *)data;
|
||||
|
@ -919,7 +919,7 @@ void free_rtype(resource_type *rtype) {
|
|||
free(rtype);
|
||||
}
|
||||
|
||||
static int free_rtype_cb(const void * match, const void * key,
|
||||
static int free_rtype_cb(void * match, const void * key,
|
||||
size_t keylen, void *cbdata)
|
||||
{
|
||||
resource_type *rtype = ((rt_entry *)match)->value;;
|
||||
|
|
|
@ -67,6 +67,46 @@ variant v)
|
|||
}
|
||||
}
|
||||
|
||||
static int missing_message_mode;
|
||||
|
||||
void message_handle_missing(int mode) {
|
||||
missing_message_mode = mode;
|
||||
}
|
||||
|
||||
static message *missing_feedback(const char *name, const struct unit *u,
|
||||
const struct region *r, struct order *ord)
|
||||
{
|
||||
if (missing_message_mode == MESSAGE_MISSING_ERROR) {
|
||||
log_error("trying to create undefined feedback of type \"%s\"\n", name);
|
||||
}
|
||||
else if (missing_message_mode == MESSAGE_MISSING_REPLACE) {
|
||||
if (strcmp(name, "missing_feedback") != 0) {
|
||||
if (!mt_find("missing_feedback")) {
|
||||
mt_create_va(mt_new("missing_feedback", NULL), "unit:unit",
|
||||
"region:region", "command:order", "name:string", MT_NEW_END);
|
||||
}
|
||||
return msg_message("missing_feedback", "unit region command name", u, r, ord, name);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static message *missing_message(const char *name) {
|
||||
if (missing_message_mode == MESSAGE_MISSING_ERROR) {
|
||||
log_error("trying to create undefined message of type \"%s\"\n", name);
|
||||
}
|
||||
else if (missing_message_mode == MESSAGE_MISSING_REPLACE) {
|
||||
log_warning("trying to create undefined message of type \"%s\"\n", name);
|
||||
if (strcmp(name, "missing_message") != 0) {
|
||||
if (!mt_find("missing_message")) {
|
||||
mt_create_va(mt_new("missing_message", NULL), "name:string", MT_NEW_END);
|
||||
}
|
||||
return msg_message("missing_message", "name", name);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct message *msg_feedback(const struct unit *u, struct order *ord,
|
||||
const char *name, const char *sig, ...)
|
||||
{
|
||||
|
@ -80,13 +120,7 @@ struct message *msg_feedback(const struct unit *u, struct order *ord,
|
|||
}
|
||||
|
||||
if (!mtype) {
|
||||
log_warning("trying to create message of unknown type \"%s\"\n", name);
|
||||
if (!mt_find("missing_feedback")) {
|
||||
mt_create_va(mt_new("missing_feedback", NULL), "unit:unit",
|
||||
"region:region", "command:order", "name:string", MT_NEW_END);
|
||||
}
|
||||
return msg_message("missing_feedback", "name unit region command",
|
||||
name, u, u->region, ord);
|
||||
return missing_feedback(name, u, u->region, ord);
|
||||
}
|
||||
|
||||
var.v = (void *)u;
|
||||
|
@ -139,28 +173,6 @@ struct message *msg_feedback(const struct unit *u, struct order *ord,
|
|||
return msg_create(mtype, args);
|
||||
}
|
||||
|
||||
static int missing_message_mode;
|
||||
|
||||
void message_handle_missing(int mode) {
|
||||
missing_message_mode = mode;
|
||||
}
|
||||
|
||||
static message *missing_message(const char *name) {
|
||||
if (missing_message_mode == MESSAGE_MISSING_ERROR) {
|
||||
log_error("trying to create undefined message of type \"%s\"\n", name);
|
||||
}
|
||||
else if (missing_message_mode == MESSAGE_MISSING_REPLACE) {
|
||||
log_warning("trying to create undefined message of type \"%s\"\n", name);
|
||||
if (strcmp(name, "missing_message") != 0) {
|
||||
if (!mt_find("missing_message")) {
|
||||
mt_create_va(mt_new("missing_message", NULL), "name:string", MT_NEW_END);
|
||||
}
|
||||
return msg_message("missing_message", "name", name);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
message *msg_message(const char *name, const char *sig, ...)
|
||||
/* msg_message("oops_error", "unit region command", u, r, cmd) */
|
||||
{
|
||||
|
|
|
@ -18,6 +18,21 @@ void test_missing_message(CuTest *tc) {
|
|||
CuAssertPtrNotNull(tc, msg);
|
||||
CuAssertPtrNotNull(tc, msg->type);
|
||||
CuAssertStrEquals(tc, msg->type->name, "missing_message");
|
||||
CuAssertStrEquals(tc, "unknown", (const char *)msg->parameters[0].v);
|
||||
msg_release(msg);
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
void test_missing_feedback(CuTest *tc) {
|
||||
message *msg;
|
||||
|
||||
test_setup();
|
||||
message_handle_missing(MESSAGE_MISSING_REPLACE);
|
||||
msg = msg_error(NULL, NULL, 77);
|
||||
CuAssertPtrNotNull(tc, msg);
|
||||
CuAssertPtrNotNull(tc, msg->type);
|
||||
CuAssertStrEquals(tc, msg->type->name, "missing_feedback");
|
||||
CuAssertStrEquals(tc, "error77", (const char *)msg->parameters[3].v);
|
||||
msg_release(msg);
|
||||
test_teardown();
|
||||
}
|
||||
|
|
|
@ -84,7 +84,7 @@ char* get_command(const order *ord, const struct locale *lang, char *sbuffer, si
|
|||
sbs_strcat(&sbs, str);
|
||||
if (ord->id < 0) {
|
||||
skill_t sk = (skill_t)(100+ord->id);
|
||||
assert(kwd == K_STUDY && sk != SK_MAGIC && sk < MAXSKILLS);
|
||||
assert((kwd == K_STUDY || kwd == K_AUTOSTUDY) && sk != SK_MAGIC && sk < MAXSKILLS);
|
||||
str = skillname(sk, lang);
|
||||
if (str) {
|
||||
if (strchr(str, ' ') == NULL) {
|
||||
|
@ -141,7 +141,8 @@ int stream_order(struct stream *out, const struct order *ord, const struct local
|
|||
if (ord->id < 0) {
|
||||
skill_t sk = (skill_t)(100 + ord->id);
|
||||
|
||||
assert(kwd == K_STUDY && sk != SK_MAGIC && sk < MAXSKILLS);
|
||||
assert(kwd == K_AUTOSTUDY || kwd == K_STUDY);
|
||||
assert(sk != SK_MAGIC && sk < MAXSKILLS);
|
||||
text = skillname(sk, lang);
|
||||
if (strchr(text, ' ') != NULL) {
|
||||
swrite(" '", 1, 2, out);
|
||||
|
@ -214,12 +215,12 @@ static int create_data(keyword_t kwd, const char *s,
|
|||
order_data *data;
|
||||
int id;
|
||||
|
||||
assert(kwd!=NOKEYWORD);
|
||||
assert(kwd != NOKEYWORD);
|
||||
|
||||
if (!s || *s == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (kwd==K_STUDY) {
|
||||
if (kwd == K_STUDY || kwd == K_AUTOSTUDY) {
|
||||
const char * sptr = s;
|
||||
skill_t sk = get_skill(parse_token_depr(&sptr), lang);
|
||||
if (sk != SK_MAGIC && sk != NOSKILL) {
|
||||
|
@ -310,12 +311,13 @@ order *parse_order(const char *s, const struct locale * lang)
|
|||
assert(lang);
|
||||
assert(s);
|
||||
if (*s != 0) {
|
||||
char token[32];
|
||||
keyword_t kwd = NOKEYWORD;
|
||||
const char *sptr = s;
|
||||
bool persistent = false, noerror = false;
|
||||
const char * p;
|
||||
char * p;
|
||||
|
||||
p = *sptr ? parse_token_depr(&sptr) : 0;
|
||||
p = parse_token(&sptr, token, sizeof(token));
|
||||
if (p) {
|
||||
while (*p == '!' || *p == '@') {
|
||||
if (*p == '!') noerror = true;
|
||||
|
@ -326,12 +328,25 @@ order *parse_order(const char *s, const struct locale * lang)
|
|||
}
|
||||
if (kwd == K_MAKE) {
|
||||
const char *sp = sptr;
|
||||
p = parse_token_depr(&sp);
|
||||
p = parse_token(&sp, token, sizeof(token));
|
||||
if (p && isparam(p, lang, P_TEMP)) {
|
||||
kwd = K_MAKETEMP;
|
||||
sptr = sp;
|
||||
}
|
||||
}
|
||||
else if (kwd == K_STUDY) {
|
||||
const char *sp = sptr;
|
||||
p = parse_token(&sp, token, sizeof(token));
|
||||
if (p && isparam(p, lang, P_AUTO)) {
|
||||
skill_t sk;
|
||||
sptr = sp;
|
||||
p = parse_token(&sp, token, sizeof(token));
|
||||
sk = get_skill(p, lang);
|
||||
if (sk == NOSKILL || !expensive_skill(sk)) {
|
||||
kwd = K_AUTOSTUDY;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (kwd != NOKEYWORD) {
|
||||
order *ord = (order *)malloc(sizeof(order));
|
||||
create_order_i(ord, kwd, sptr, persistent, noerror, lang);
|
||||
|
@ -366,6 +381,7 @@ bool is_repeated(keyword_t kwd)
|
|||
case K_STEAL:
|
||||
case K_SABOTAGE:
|
||||
case K_STUDY:
|
||||
case K_AUTOSTUDY:
|
||||
case K_TEACH:
|
||||
case K_GROW:
|
||||
case K_PLANT:
|
||||
|
@ -406,6 +422,7 @@ bool is_exclusive(const order * ord)
|
|||
case K_STEAL:
|
||||
case K_SABOTAGE:
|
||||
case K_STUDY:
|
||||
case K_AUTOSTUDY:
|
||||
case K_TEACH:
|
||||
case K_GROW:
|
||||
case K_PLANT:
|
||||
|
@ -447,6 +464,7 @@ bool is_long(keyword_t kwd)
|
|||
case K_STEAL:
|
||||
case K_SABOTAGE:
|
||||
case K_STUDY:
|
||||
case K_AUTOSTUDY:
|
||||
case K_TEACH:
|
||||
case K_GROW:
|
||||
case K_PLANT:
|
||||
|
@ -541,7 +559,7 @@ keyword_t init_order(const struct order *ord, const struct locale *lang)
|
|||
|
||||
assert(sk < MAXSKILLS);
|
||||
assert(lang);
|
||||
assert(kwd == K_STUDY);
|
||||
assert(kwd == K_STUDY || kwd == K_AUTOSTUDY);
|
||||
str = skillname(sk, lang);
|
||||
if (strchr(str, ' ') == NULL) {
|
||||
init_tokens_str(str);
|
||||
|
@ -575,7 +593,7 @@ keyword_t init_order_depr(const struct order *ord)
|
|||
{
|
||||
if (ord) {
|
||||
keyword_t kwd = ORD_KEYWORD(ord);
|
||||
assert(kwd != K_STUDY);
|
||||
assert(kwd != K_STUDY && kwd != K_AUTOSTUDY);
|
||||
}
|
||||
return init_order(ord, NULL);
|
||||
}
|
||||
|
|
|
@ -113,6 +113,43 @@ static void test_parse_make(CuTest *tc) {
|
|||
test_teardown();
|
||||
}
|
||||
|
||||
static void test_parse_autostudy(CuTest *tc) {
|
||||
char cmd[32];
|
||||
order *ord;
|
||||
struct locale * lang;
|
||||
|
||||
test_setup();
|
||||
lang = get_or_create_locale("en");
|
||||
locale_setstring(lang, mkname("skill", skillnames[SK_ENTERTAINMENT]), "Entertainment");
|
||||
locale_setstring(lang, mkname("skill", skillnames[SK_MAGIC]), "Magic");
|
||||
locale_setstring(lang, mkname("skill", skillnames[SK_TACTICS]), "Tactics");
|
||||
locale_setstring(lang, keyword(K_STUDY), "STUDY");
|
||||
locale_setstring(lang, keyword(K_AUTOSTUDY), "AUTOSTUDY");
|
||||
locale_setstring(lang, parameters[P_AUTO], "AUTO");
|
||||
init_locale(lang);
|
||||
|
||||
ord = parse_order("STUDY AUTO Entertainment", lang);
|
||||
CuAssertPtrNotNull(tc, ord);
|
||||
CuAssertIntEquals(tc, K_AUTOSTUDY, getkeyword(ord));
|
||||
CuAssertStrEquals(tc, "AUTOSTUDY Entertainment", get_command(ord, lang, cmd, sizeof(cmd)));
|
||||
|
||||
CuAssertIntEquals(tc, K_AUTOSTUDY, init_order(ord, lang));
|
||||
CuAssertStrEquals(tc, "Entertainment", getstrtoken());
|
||||
free_order(ord);
|
||||
|
||||
ord = parse_order("STUDY AUTO Magic", lang);
|
||||
CuAssertIntEquals(tc, K_STUDY, getkeyword(ord));
|
||||
CuAssertStrEquals(tc, "STUDY Magic", get_command(ord, lang, cmd, sizeof(cmd)));
|
||||
free_order(ord);
|
||||
|
||||
ord = parse_order("STUDY AUTO Tactics", lang);
|
||||
CuAssertIntEquals(tc, K_STUDY, getkeyword(ord));
|
||||
CuAssertStrEquals(tc, "STUDY Tactics", get_command(ord, lang, cmd, sizeof(cmd)));
|
||||
free_order(ord);
|
||||
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
static void test_parse_make_temp(CuTest *tc) {
|
||||
char cmd[32];
|
||||
order *ord;
|
||||
|
@ -130,7 +167,7 @@ static void test_parse_make_temp(CuTest *tc) {
|
|||
CuAssertIntEquals(tc, K_MAKETEMP, getkeyword(ord));
|
||||
CuAssertStrEquals(tc, "MAKETEMP herp", get_command(ord, lang, cmd, sizeof(cmd)));
|
||||
|
||||
CuAssertIntEquals(tc, K_MAKETEMP, init_order_depr(ord));
|
||||
CuAssertIntEquals(tc, K_MAKETEMP, init_order(ord, lang));
|
||||
CuAssertStrEquals(tc, "herp", getstrtoken());
|
||||
free_order(ord);
|
||||
test_teardown();
|
||||
|
@ -153,7 +190,7 @@ static void test_parse_maketemp(CuTest *tc) {
|
|||
CuAssertPtrNotNull(tc, ord);
|
||||
CuAssertStrEquals(tc, "MAKETEMP herp", get_command(ord, lang, cmd, sizeof(cmd)));
|
||||
CuAssertIntEquals(tc, K_MAKETEMP, getkeyword(ord));
|
||||
CuAssertIntEquals(tc, K_MAKETEMP, init_order_depr(ord));
|
||||
CuAssertIntEquals(tc, K_MAKETEMP, init_order(ord, lang));
|
||||
CuAssertStrEquals(tc, "herp", getstrtoken());
|
||||
free_order(ord);
|
||||
test_teardown();
|
||||
|
@ -167,7 +204,7 @@ static void test_init_order(CuTest *tc) {
|
|||
|
||||
lang = get_or_create_locale("en");
|
||||
ord = create_order(K_MAKETEMP, lang, "hurr durr");
|
||||
CuAssertIntEquals(tc, K_MAKETEMP, init_order_depr(ord));
|
||||
CuAssertIntEquals(tc, K_MAKETEMP, init_order(ord, lang));
|
||||
CuAssertStrEquals(tc, "hurr", getstrtoken());
|
||||
CuAssertStrEquals(tc, "durr", getstrtoken());
|
||||
free_order(ord);
|
||||
|
@ -512,6 +549,7 @@ static void test_create_order_long(CuTest *tc) {
|
|||
stream_order(&out, ord, lang, true);
|
||||
out.api->rewind(out.handle);
|
||||
out.api->readln(out.handle, buffer, sizeof(buffer));
|
||||
CuAssertIntEquals(tc, 1026, strlen(buffer));
|
||||
mstream_done(&out);
|
||||
free_order(ord);
|
||||
test_teardown();
|
||||
|
@ -547,6 +585,7 @@ CuSuite *get_order_suite(void)
|
|||
SUITE_ADD_TEST(suite, test_study_order_quoted);
|
||||
SUITE_ADD_TEST(suite, test_parse_order);
|
||||
SUITE_ADD_TEST(suite, test_parse_make);
|
||||
SUITE_ADD_TEST(suite, test_parse_autostudy);
|
||||
SUITE_ADD_TEST(suite, test_parse_make_temp);
|
||||
SUITE_ADD_TEST(suite, test_parse_maketemp);
|
||||
SUITE_ADD_TEST(suite, test_init_order);
|
||||
|
|
|
@ -716,7 +716,10 @@ const item_type *r_luxury(const region * r)
|
|||
|
||||
int r_demand(const region * r, const luxury_type * ltype)
|
||||
{
|
||||
struct demand *d = r->land->demands;
|
||||
struct demand *d;
|
||||
|
||||
assert(r && r->land);
|
||||
d = r->land->demands;
|
||||
while (d && d->type != ltype)
|
||||
d = d->next;
|
||||
if (!d)
|
||||
|
@ -824,7 +827,7 @@ void free_land(land_region * lr)
|
|||
free(lr);
|
||||
}
|
||||
|
||||
void region_setresource(region * r, const resource_type * rtype, int value)
|
||||
void region_setresource(region * r, const struct resource_type *rtype, int value)
|
||||
{
|
||||
rawmaterial *rm = r->resources;
|
||||
while (rm) {
|
||||
|
@ -867,7 +870,18 @@ void region_setresource(region * r, const resource_type * rtype, int value)
|
|||
}
|
||||
}
|
||||
|
||||
int region_getresource(const region * r, const resource_type * rtype)
|
||||
int region_getresource_level(const region * r, const struct resource_type * rtype)
|
||||
{
|
||||
const rawmaterial *rm;
|
||||
for (rm = r->resources; rm; rm = rm->next) {
|
||||
if (rm->rtype == rtype) {
|
||||
return rm->level;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int region_getresource(const region * r, const struct resource_type *rtype)
|
||||
{
|
||||
const rawmaterial *rm;
|
||||
for (rm = r->resources; rm; rm = rm->next) {
|
||||
|
@ -1048,6 +1062,43 @@ int fix_demand(region * rd) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
void init_region(region *r)
|
||||
{
|
||||
static int changed;
|
||||
static const terrain_type *t_plain;
|
||||
const terrain_type * terrain = r->terrain;
|
||||
int horses = 0, trees = 0;
|
||||
if (terrain_changed(&changed)) {
|
||||
t_plain = get_terrain(terrainnames[T_PLAIN]);
|
||||
}
|
||||
if (terrain->size>0) {
|
||||
horses = rng_int() % (terrain->size / 50);
|
||||
trees = terrain->size * (30 + rng_int() % 40) / 1000;
|
||||
}
|
||||
if (t_plain && terrain == t_plain) {
|
||||
rsethorses(r, horses);
|
||||
if (chance(0.4)) {
|
||||
rsettrees(r, 2, trees);
|
||||
}
|
||||
}
|
||||
else if (trees>0 && chance(0.2)) {
|
||||
rsettrees(r, 2, trees);
|
||||
}
|
||||
else {
|
||||
rsettrees(r, 2, 0);
|
||||
}
|
||||
rsettrees(r, 1, rtrees(r, 2) / 4);
|
||||
rsettrees(r, 0, rtrees(r, 2) / 8);
|
||||
|
||||
if (!fval(r, RF_CHAOTIC)) {
|
||||
int peasants;
|
||||
peasants = (region_maxworkers(r) * (20 + dice(6, 10))) / 100;
|
||||
rsetpeasants(r, MAX(100, peasants));
|
||||
rsetmoney(r, rpeasants(r) * ((wage(r, NULL, NULL,
|
||||
INT_MAX) + 1) + rng_int() % 5));
|
||||
}
|
||||
}
|
||||
|
||||
void terraform_region(region * r, const terrain_type * terrain)
|
||||
{
|
||||
/* Resourcen, die nicht mehr vorkommen können, löschen */
|
||||
|
@ -1195,40 +1246,8 @@ void terraform_region(region * r, const terrain_type * terrain)
|
|||
else
|
||||
freset(r, RF_MALLORN);
|
||||
}
|
||||
}
|
||||
|
||||
if (oldterrain == NULL || terrain->size != oldterrain->size) {
|
||||
static int changed;
|
||||
static const terrain_type *t_plain;
|
||||
int horses = 0, trees = 0;
|
||||
if (terrain_changed(&changed)) {
|
||||
t_plain = get_terrain(terrainnames[T_PLAIN]);
|
||||
}
|
||||
if (terrain->size>0) {
|
||||
horses = rng_int() % (terrain->size / 50);
|
||||
trees = terrain->size * (30 + rng_int() % 40) / 1000;
|
||||
}
|
||||
if (t_plain && terrain == t_plain) {
|
||||
rsethorses(r, horses);
|
||||
if (chance(0.4)) {
|
||||
rsettrees(r, 2, trees);
|
||||
}
|
||||
}
|
||||
else if (trees>0 && chance(0.2)) {
|
||||
rsettrees(r, 2, trees);
|
||||
}
|
||||
else {
|
||||
rsettrees(r, 2, 0);
|
||||
}
|
||||
rsettrees(r, 1, rtrees(r, 2) / 4);
|
||||
rsettrees(r, 0, rtrees(r, 2) / 8);
|
||||
|
||||
if (!fval(r, RF_CHAOTIC)) {
|
||||
int peasants;
|
||||
peasants = (region_maxworkers(r) * (20 + dice(6, 10))) / 100;
|
||||
rsetpeasants(r, MAX(100, peasants));
|
||||
rsetmoney(r, rpeasants(r) * ((wage(r, NULL, NULL,
|
||||
INT_MAX) + 1) + rng_int() % 5));
|
||||
if (oldterrain == NULL || terrain->size != oldterrain->size) {
|
||||
init_region(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -228,6 +228,7 @@ extern "C" {
|
|||
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);
|
||||
|
||||
extern const int delta_x[MAXDIRECTIONS];
|
||||
|
@ -260,6 +261,8 @@ extern "C" {
|
|||
void region_setname(struct region *self, const char *name);
|
||||
const char *region_getinfo(const struct region *self);
|
||||
void region_setinfo(struct region *self, const char *name);
|
||||
int region_getresource_level(const struct region * r,
|
||||
const struct resource_type * rtype);
|
||||
int region_getresource(const struct region *r,
|
||||
const struct resource_type *rtype);
|
||||
void region_setresource(struct region *r, const struct resource_type *rtype,
|
||||
|
|
|
@ -46,8 +46,6 @@ void update_resources(region * r)
|
|||
}
|
||||
}
|
||||
|
||||
extern int dice_rand(const char *s);
|
||||
|
||||
static void update_resource(struct rawmaterial *res, double modifier)
|
||||
{
|
||||
double amount = (res->level - res->startlevel) / 100.0 * res->divisor + 1;
|
||||
|
@ -59,6 +57,15 @@ static void update_resource(struct rawmaterial *res, double modifier)
|
|||
assert(res->amount > 0);
|
||||
}
|
||||
|
||||
void set_resource(struct rawmaterial *rm, int level, int base, int divisor)
|
||||
{
|
||||
rm->level = level;
|
||||
rm->startlevel = level;
|
||||
rm->base = base;
|
||||
rm->amount = base;
|
||||
rm->divisor = divisor;
|
||||
}
|
||||
|
||||
struct rawmaterial *
|
||||
add_resource(region * r, int level, int base, int divisor,
|
||||
const resource_type * rtype)
|
||||
|
@ -67,13 +74,9 @@ const resource_type * rtype)
|
|||
|
||||
rm->next = r->resources;
|
||||
r->resources = rm;
|
||||
rm->level = level;
|
||||
rm->startlevel = level;
|
||||
rm->base = base;
|
||||
rm->amount = base;
|
||||
rm->divisor = divisor;
|
||||
rm->flags = 0;
|
||||
rm->rtype = rtype;
|
||||
set_resource(rm, level, base, divisor);
|
||||
return rm;
|
||||
}
|
||||
|
||||
|
|
|
@ -70,6 +70,7 @@ extern "C" {
|
|||
const struct resource_type *);
|
||||
struct rawmaterial_type *rmt_get(const struct resource_type *);
|
||||
|
||||
void set_resource(struct rawmaterial *rm, int level, int base, int divisor);
|
||||
struct rawmaterial *add_resource(struct region *r, int level,
|
||||
int base, int divisor, const struct resource_type *rtype);
|
||||
struct rawmaterial_type *rmt_create(struct resource_type *rtype);
|
||||
|
|
|
@ -1493,7 +1493,9 @@ int read_game(gamedata *data)
|
|||
if (r->flags & RF_LIGHTHOUSE) {
|
||||
building *b;
|
||||
for (b = r->buildings; b; b = b->next) {
|
||||
update_lighthouse(b);
|
||||
if (is_lighthouse(b->type)) {
|
||||
update_lighthouse(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -124,9 +124,9 @@ extern "C" {
|
|||
extern void write_ship_reference(const struct ship *sh,
|
||||
struct storage *store);
|
||||
|
||||
extern void remove_ship(struct ship **slist, struct ship *s);
|
||||
extern void free_ship(struct ship *s);
|
||||
extern void free_ships(void);
|
||||
void remove_ship(struct ship **slist, struct ship *s);
|
||||
void free_ship(struct ship *s);
|
||||
void free_ships(void);
|
||||
|
||||
const char *ship_getname(const struct ship *sh);
|
||||
void ship_setname(struct ship *self, const char *name);
|
||||
|
|
|
@ -33,7 +33,6 @@ static void test_create_duplicate_spell(CuTest * tc)
|
|||
strlist *sl = 0;
|
||||
|
||||
test_setup();
|
||||
test_inject_messagetypes();
|
||||
test_log_stderr(0); /* suppress the "duplicate spell" error message */
|
||||
log = test_log_start(LOG_CPERROR, &sl);
|
||||
|
||||
|
|
|
@ -130,6 +130,7 @@ typedef enum {
|
|||
P_FACTIONSTEALTH,
|
||||
P_TREES,
|
||||
P_ALLIANCE,
|
||||
P_AUTO,
|
||||
MAXPARAMS,
|
||||
NOPARAM
|
||||
} param_t;
|
||||
|
|
|
@ -1310,13 +1310,12 @@ int eff_skill(const unit * u, const skill *sv, const region *r)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int effskill_study(const unit * u, skill_t sk, const region * r)
|
||||
int effskill_study(const unit * u, skill_t sk)
|
||||
{
|
||||
skill *sv = unit_skill(u, sk);
|
||||
if (sv && sv->level > 0) {
|
||||
int mlevel = sv->level;
|
||||
if (!r) r = u->region;
|
||||
mlevel += get_modifier(u, sv->id, sv->level, r, true);
|
||||
mlevel += get_modifier(u, sv->id, sv->level, u->region, true);
|
||||
if (mlevel > 0)
|
||||
return mlevel;
|
||||
}
|
||||
|
@ -1854,10 +1853,6 @@ bool unit_name_equals_race(const unit *u) {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool unit_can_study(const unit *u) {
|
||||
return !((u_race(u)->flags & RCF_NOLEARN) || fval(u, UFL_WERE));
|
||||
}
|
||||
|
||||
static int read_newunitid(const faction * f, const region * r)
|
||||
{
|
||||
int n;
|
||||
|
|
|
@ -163,7 +163,7 @@ extern "C" {
|
|||
void clone_men(const struct unit *src, struct unit *dst, int n); /* like transfer, but do not subtract from src */
|
||||
|
||||
int eff_skill(const struct unit *u, const struct skill *sv, const struct region *r);
|
||||
int effskill_study(const struct unit *u, skill_t sk, const struct region *r);
|
||||
int effskill_study(const struct unit *u, skill_t sk);
|
||||
|
||||
int get_modifier(const struct unit *u, skill_t sk, int level,
|
||||
const struct region *r, bool noitem);
|
||||
|
@ -246,7 +246,6 @@ extern "C" {
|
|||
const char *unitname(const struct unit *u);
|
||||
char *write_unitname(const struct unit *u, char *buffer, size_t size);
|
||||
bool unit_name_equals_race(const struct unit *u);
|
||||
bool unit_can_study(const struct unit *u);
|
||||
|
||||
/* getunit results: */
|
||||
#define GET_UNIT 0
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
#ifndef ERESSEA_VERSION
|
||||
/* the version number, if it was not passed to make with -D */
|
||||
#define ERESSEA_VERSION "3.16.0"
|
||||
#define ERESSEA_VERSION "3.18.0"
|
||||
#endif
|
||||
|
||||
const char *eressea_version(void) {
|
||||
|
|
|
@ -149,5 +149,6 @@ const char *keywords[MAXKEYWORDS] = {
|
|||
"promote",
|
||||
"pay",
|
||||
"loot",
|
||||
"autostudy",
|
||||
};
|
||||
|
||||
|
|
|
@ -72,6 +72,7 @@ extern "C"
|
|||
K_PROMOTION,
|
||||
K_PAY,
|
||||
K_LOOT,
|
||||
K_AUTOSTUDY,
|
||||
MAXKEYWORDS,
|
||||
NOKEYWORD
|
||||
} keyword_t;
|
||||
|
|
45
src/laws.c
45
src/laws.c
|
@ -26,6 +26,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
#include <modules/gmcmd.h>
|
||||
|
||||
#include "alchemy.h"
|
||||
#include "automate.h"
|
||||
#include "battle.h"
|
||||
#include "economy.h"
|
||||
#include "keyword.h"
|
||||
|
@ -2058,17 +2059,6 @@ int mail_cmd(unit * u, struct order *ord)
|
|||
break;
|
||||
}
|
||||
else {
|
||||
attrib *a = a_find(u2->attribs, &at_eventhandler);
|
||||
if (a != NULL) {
|
||||
event_arg args[3];
|
||||
args[0].data.v = (void *)s;
|
||||
args[0].type = "string";
|
||||
args[1].data.v = (void *)u;
|
||||
args[1].type = "unit";
|
||||
args[2].type = NULL;
|
||||
handle_event(a, "message", args);
|
||||
}
|
||||
|
||||
mailunit(r, u, n, ord, s);
|
||||
}
|
||||
return 0;
|
||||
|
@ -2590,6 +2580,7 @@ void sinkships(struct region * r)
|
|||
}
|
||||
}
|
||||
if (sh->damage >= sh->size * DAMAGE_SCALE) {
|
||||
sink_ship(sh);
|
||||
remove_ship(shp, sh);
|
||||
}
|
||||
if (*shp == sh)
|
||||
|
@ -3646,6 +3637,24 @@ void add_proc_unit(int priority, void(*process) (unit *), const char *name)
|
|||
}
|
||||
}
|
||||
|
||||
bool long_order_allowed(const unit *u)
|
||||
{
|
||||
const region *r = u->region;
|
||||
if (fval(u, UFL_LONGACTION)) {
|
||||
/* this message was already given in laws.update_long_order
|
||||
cmistake(u, ord, 52, MSG_PRODUCE);
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
else if (fval(r->terrain, SEA_REGION)
|
||||
&& u_race(u) != get_race(RC_AQUARIAN)
|
||||
&& !(u_race(u)->flags & RCF_SWIM)) {
|
||||
/* error message disabled by popular demand */
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* per priority, execute processors in order from PR_GLOBAL down to PR_ORDER */
|
||||
void process(void)
|
||||
{
|
||||
|
@ -3715,16 +3724,7 @@ void process(void)
|
|||
cmistake(u, ord, 224, MSG_MAGIC);
|
||||
ord = NULL;
|
||||
}
|
||||
else if (fval(u, UFL_LONGACTION)) {
|
||||
/* this message was already given in laws.update_long_order
|
||||
cmistake(u, ord, 52, MSG_PRODUCE);
|
||||
*/
|
||||
ord = NULL;
|
||||
}
|
||||
else if (fval(r->terrain, SEA_REGION)
|
||||
&& u_race(u) != get_race(RC_AQUARIAN)
|
||||
&& !(u_race(u)->flags & RCF_SWIM)) {
|
||||
/* error message disabled by popular demand */
|
||||
else if (!long_order_allowed(u)) {
|
||||
ord = NULL;
|
||||
}
|
||||
}
|
||||
|
@ -4011,6 +4011,7 @@ void init_processor(void)
|
|||
}
|
||||
|
||||
p += 10;
|
||||
add_proc_region(p, do_autostudy, "study automation");
|
||||
add_proc_order(p, K_TEACH, teach_cmd, PROC_THISORDER | PROC_LONGORDER,
|
||||
"Lehren");
|
||||
p += 10;
|
||||
|
@ -4165,7 +4166,7 @@ void update_subscriptions(void)
|
|||
/** determine if unit can be seen by faction
|
||||
* @param f -- the observiong faction
|
||||
* @param u -- the unit that is observed
|
||||
* @param r -- the region that u is obesrved in (see below)
|
||||
* @param r -- the region that u is obesrved from (see below)
|
||||
* @param m -- terrain modifier to stealth
|
||||
*
|
||||
* r kann != u->region sein, wenn es um Durchreisen geht,
|
||||
|
|
|
@ -66,6 +66,7 @@ extern "C" {
|
|||
void update_long_order(struct unit *u);
|
||||
void sinkships(struct region * r);
|
||||
void do_enter(struct region *r, bool is_final_attempt);
|
||||
bool long_order_allowed(const struct unit *u);
|
||||
|
||||
int password_cmd(struct unit *u, struct order *ord);
|
||||
int banner_cmd(struct unit *u, struct order *ord);
|
||||
|
|
113
src/laws.test.c
113
src/laws.test.c
|
@ -153,8 +153,8 @@ static void test_enter_building(CuTest * tc)
|
|||
rc->flags = RCF_SWIM;
|
||||
u->building = 0;
|
||||
CuAssertIntEquals(tc, 0, enter_building(u, NULL, b->no, false));
|
||||
CuAssertPtrEquals(tc, 0, u->building);
|
||||
CuAssertPtrEquals(tc, 0, u->faction->msgs);
|
||||
CuAssertPtrEquals(tc, NULL, u->building);
|
||||
CuAssertPtrEquals(tc, NULL, u->faction->msgs);
|
||||
|
||||
CuAssertIntEquals(tc, 0, enter_building(u, NULL, b->no, true));
|
||||
CuAssertPtrNotNull(tc, u->faction->msgs);
|
||||
|
@ -170,7 +170,6 @@ static void test_enter_ship(CuTest * tc)
|
|||
race * rc;
|
||||
|
||||
test_setup();
|
||||
|
||||
r = test_create_region(0, 0, NULL);
|
||||
rc = test_create_race("smurf");
|
||||
u = test_create_unit(test_create_faction(rc), r);
|
||||
|
@ -194,8 +193,8 @@ static void test_enter_ship(CuTest * tc)
|
|||
rc->flags = RCF_SWIM;
|
||||
u->ship = 0;
|
||||
CuAssertIntEquals(tc, 0, enter_ship(u, NULL, sh->no, false));
|
||||
CuAssertPtrEquals(tc, 0, u->ship);
|
||||
CuAssertPtrEquals(tc, 0, u->faction->msgs);
|
||||
CuAssertPtrEquals(tc, NULL, u->ship);
|
||||
CuAssertPtrEquals(tc, NULL, u->faction->msgs);
|
||||
|
||||
CuAssertIntEquals(tc, 0, enter_ship(u, NULL, sh->no, true));
|
||||
CuAssertPtrNotNull(tc, u->faction->msgs);
|
||||
|
@ -486,6 +485,10 @@ static void test_limit_new_units(CuTest * tc)
|
|||
alliance *al;
|
||||
|
||||
test_setup();
|
||||
mt_create_va(mt_new("too_many_units_in_faction", NULL), "unit:unit",
|
||||
"region:region", "command:order", "allowed:int", MT_NEW_END);
|
||||
mt_create_va(mt_new("too_many_units_in_alliance", NULL), "unit:unit",
|
||||
"region:region", "command:order", "allowed:int", MT_NEW_END);
|
||||
al = makealliance(1, "Hodor");
|
||||
f = test_create_faction(NULL);
|
||||
u = test_create_unit(f, test_create_region(0, 0, NULL));
|
||||
|
@ -901,6 +904,9 @@ static unit * setup_name_cmd(void) {
|
|||
faction *f;
|
||||
|
||||
test_setup();
|
||||
mt_create_error(84);
|
||||
mt_create_error(148);
|
||||
mt_create_error(12);
|
||||
mt_create_va(mt_new("renamed_building_seen", NULL), "renamer:unit", "region:region", "building:building", MT_NEW_END);
|
||||
mt_create_va(mt_new("renamed_building_notseen", NULL), "region:region", "building:building", MT_NEW_END);
|
||||
f = test_create_faction(NULL);
|
||||
|
@ -1049,8 +1055,8 @@ static void test_long_order_normal(CuTest *tc) {
|
|||
CuAssertIntEquals(tc, 0, fval(u, UFL_MOVED));
|
||||
CuAssertIntEquals(tc, 0, fval(u, UFL_LONGACTION));
|
||||
CuAssertPtrNotNull(tc, u->orders);
|
||||
CuAssertPtrEquals(tc, 0, u->faction->msgs);
|
||||
CuAssertPtrEquals(tc, 0, u->old_orders);
|
||||
CuAssertPtrEquals(tc, NULL, u->faction->msgs);
|
||||
CuAssertPtrEquals(tc, NULL, u->old_orders);
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
|
@ -1060,9 +1066,9 @@ static void test_long_order_none(CuTest *tc) {
|
|||
test_setup();
|
||||
u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL));
|
||||
update_long_order(u);
|
||||
CuAssertPtrEquals(tc, 0, u->thisorder);
|
||||
CuAssertPtrEquals(tc, 0, u->orders);
|
||||
CuAssertPtrEquals(tc, 0, u->faction->msgs);
|
||||
CuAssertPtrEquals(tc, NULL, u->thisorder);
|
||||
CuAssertPtrEquals(tc, NULL, u->orders);
|
||||
CuAssertPtrEquals(tc, NULL, u->faction->msgs);
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
|
@ -1074,9 +1080,9 @@ static void test_long_order_cast(CuTest *tc) {
|
|||
unit_addorder(u, create_order(K_CAST, u->faction->locale, NULL));
|
||||
unit_addorder(u, create_order(K_CAST, u->faction->locale, NULL));
|
||||
update_long_order(u);
|
||||
CuAssertPtrEquals(tc, 0, u->thisorder);
|
||||
CuAssertPtrEquals(tc, NULL, u->thisorder);
|
||||
CuAssertPtrNotNull(tc, u->orders);
|
||||
CuAssertPtrEquals(tc, 0, u->faction->msgs);
|
||||
CuAssertPtrEquals(tc, NULL, u->faction->msgs);
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
|
@ -1089,9 +1095,9 @@ static void test_long_order_buy_sell(CuTest *tc) {
|
|||
unit_addorder(u, create_order(K_SELL, u->faction->locale, NULL));
|
||||
unit_addorder(u, create_order(K_SELL, u->faction->locale, NULL));
|
||||
update_long_order(u);
|
||||
CuAssertPtrEquals(tc, 0, u->thisorder);
|
||||
CuAssertPtrEquals(tc, NULL, u->thisorder);
|
||||
CuAssertPtrNotNull(tc, u->orders);
|
||||
CuAssertPtrEquals(tc, 0, u->faction->msgs);
|
||||
CuAssertPtrEquals(tc, NULL, u->faction->msgs);
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
|
@ -1099,6 +1105,7 @@ static void test_long_order_multi_long(CuTest *tc) {
|
|||
/* TODO: write more tests */
|
||||
unit *u;
|
||||
test_setup();
|
||||
mt_create_error(52);
|
||||
u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL));
|
||||
unit_addorder(u, create_order(K_MOVE, u->faction->locale, NULL));
|
||||
unit_addorder(u, create_order(K_DESTROY, u->faction->locale, NULL));
|
||||
|
@ -1113,11 +1120,12 @@ static void test_long_order_multi_buy(CuTest *tc) {
|
|||
/* TODO: write more tests */
|
||||
unit *u;
|
||||
test_setup();
|
||||
mt_create_error(52);
|
||||
u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL));
|
||||
unit_addorder(u, create_order(K_BUY, u->faction->locale, 0));
|
||||
unit_addorder(u, create_order(K_BUY, u->faction->locale, 0));
|
||||
update_long_order(u);
|
||||
CuAssertPtrEquals(tc, 0, u->thisorder);
|
||||
CuAssertPtrEquals(tc, NULL, u->thisorder);
|
||||
CuAssertPtrNotNull(tc, u->orders);
|
||||
CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "error52"));
|
||||
test_teardown();
|
||||
|
@ -1132,9 +1140,9 @@ static void test_long_order_multi_sell(CuTest *tc) {
|
|||
unit_addorder(u, create_order(K_BUY, u->faction->locale, 0));
|
||||
unit_addorder(u, create_order(K_SELL, u->faction->locale, 0));
|
||||
update_long_order(u);
|
||||
CuAssertPtrEquals(tc, 0, u->thisorder);
|
||||
CuAssertPtrEquals(tc, NULL, u->thisorder);
|
||||
CuAssertPtrNotNull(tc, u->orders);
|
||||
CuAssertPtrEquals(tc, 0, u->faction->msgs);
|
||||
CuAssertPtrEquals(tc, NULL, u->faction->msgs);
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
|
@ -1142,11 +1150,12 @@ static void test_long_order_buy_cast(CuTest *tc) {
|
|||
/* TODO: write more tests */
|
||||
unit *u;
|
||||
test_setup();
|
||||
mt_create_error(52);
|
||||
u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL));
|
||||
unit_addorder(u, create_order(K_BUY, u->faction->locale, 0));
|
||||
unit_addorder(u, create_order(K_CAST, u->faction->locale, 0));
|
||||
update_long_order(u);
|
||||
CuAssertPtrEquals(tc, 0, u->thisorder);
|
||||
CuAssertPtrEquals(tc, NULL, u->thisorder);
|
||||
CuAssertPtrNotNull(tc, u->orders);
|
||||
CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "error52"));
|
||||
test_teardown();
|
||||
|
@ -1164,7 +1173,7 @@ static void test_long_order_hungry(CuTest *tc) {
|
|||
update_long_order(u);
|
||||
CuAssertIntEquals(tc, K_WORK, getkeyword(u->thisorder));
|
||||
CuAssertPtrNotNull(tc, u->orders);
|
||||
CuAssertPtrEquals(tc, 0, u->faction->msgs);
|
||||
CuAssertPtrEquals(tc, NULL, u->faction->msgs);
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
|
@ -1174,9 +1183,10 @@ static void test_ally_cmd_errors(CuTest *tc) {
|
|||
order *ord;
|
||||
|
||||
test_setup();
|
||||
mt_create_error(66);
|
||||
u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL));
|
||||
fid = u->faction->no + 1;
|
||||
CuAssertPtrEquals(tc, 0, findfaction(fid));
|
||||
CuAssertPtrEquals(tc, NULL, findfaction(fid));
|
||||
|
||||
ord = create_order(K_ALLY, u->faction->locale, itoa36(fid));
|
||||
ally_cmd(u, ord);
|
||||
|
@ -1273,25 +1283,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, 0, u->faction->msgs);
|
||||
CuAssertPtrEquals(tc, NULL, u->faction->msgs);
|
||||
CuAssertIntEquals(tc, HELP_ALL, alliedfaction(0, u->faction, f, HELP_ALL));
|
||||
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, 0, u->faction->msgs);
|
||||
CuAssertPtrEquals(tc, NULL, u->faction->msgs);
|
||||
CuAssertIntEquals(tc, 0, alliedfaction(0, u->faction, f, HELP_ALL));
|
||||
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, 0, u->faction->msgs);
|
||||
CuAssertPtrEquals(tc, NULL, u->faction->msgs);
|
||||
CuAssertIntEquals(tc, HELP_GUARD, alliedfaction(0, u->faction, f, HELP_ALL));
|
||||
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, 0, u->faction->msgs);
|
||||
CuAssertPtrEquals(tc, NULL, u->faction->msgs);
|
||||
CuAssertIntEquals(tc, 0, alliedfaction(0, u->faction, f, HELP_ALL));
|
||||
free_order(ord);
|
||||
|
||||
|
@ -1325,6 +1335,8 @@ static unit * setup_mail_cmd(void) {
|
|||
faction *f;
|
||||
|
||||
test_setup();
|
||||
mt_create_error(66);
|
||||
mt_create_error(30);
|
||||
mt_create_va(mt_new("regionmessage", NULL), "region:region", "sender:unit", "string:string", MT_NEW_END);
|
||||
mt_create_va(mt_new("unitmessage", NULL), "region:region", "sender:unit", "string:string", "unit:unit", MT_NEW_END);
|
||||
mt_create_va(mt_new("mail_result", NULL), "message:string", "unit:unit", MT_NEW_END);
|
||||
|
@ -1383,7 +1395,7 @@ static void test_mail_unit_no_msg(CuTest *tc) {
|
|||
f = u->faction;
|
||||
ord = create_order(K_MAIL, f->locale, "%s %s", LOC(f->locale, parameters[P_UNIT]), itoa36(u->no));
|
||||
mail_cmd(u, ord);
|
||||
CuAssertPtrEquals(tc, 0, test_find_messagetype(f->msgs, "unitmessage"));
|
||||
CuAssertPtrEquals(tc, NULL, test_find_messagetype(f->msgs, "unitmessage"));
|
||||
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error30"));
|
||||
free_order(ord);
|
||||
test_teardown();
|
||||
|
@ -1398,7 +1410,7 @@ static void test_mail_faction_no_msg(CuTest *tc) {
|
|||
f = u->faction;
|
||||
ord = create_order(K_MAIL, f->locale, "%s %s", LOC(f->locale, parameters[P_FACTION]), itoa36(f->no));
|
||||
mail_cmd(u, ord);
|
||||
CuAssertPtrEquals(tc, 0, test_find_messagetype(f->msgs, "regionmessage"));
|
||||
CuAssertPtrEquals(tc, NULL, test_find_messagetype(f->msgs, "regionmessage"));
|
||||
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error30"));
|
||||
free_order(ord);
|
||||
test_teardown();
|
||||
|
@ -1413,7 +1425,7 @@ static void test_mail_faction_no_target(CuTest *tc) {
|
|||
f = u->faction;
|
||||
ord = create_order(K_MAIL, f->locale, "%s %s", LOC(f->locale, parameters[P_FACTION]), itoa36(f->no+1));
|
||||
mail_cmd(u, ord);
|
||||
CuAssertPtrEquals(tc, 0, test_find_messagetype(f->msgs, "regionmessage"));
|
||||
CuAssertPtrEquals(tc, NULL, test_find_messagetype(f->msgs, "regionmessage"));
|
||||
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error66"));
|
||||
free_order(ord);
|
||||
test_teardown();
|
||||
|
@ -1428,7 +1440,7 @@ static void test_mail_region_no_msg(CuTest *tc) {
|
|||
f = u->faction;
|
||||
ord = create_order(K_MAIL, f->locale, LOC(f->locale, parameters[P_REGION]));
|
||||
mail_cmd(u, ord);
|
||||
CuAssertPtrEquals(tc, 0, test_find_messagetype(u->region->msgs, "mail_result"));
|
||||
CuAssertPtrEquals(tc, NULL, test_find_messagetype(u->region->msgs, "mail_result"));
|
||||
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error30"));
|
||||
free_order(ord);
|
||||
test_teardown();
|
||||
|
@ -1444,6 +1456,8 @@ static void test_show_without_item(CuTest *tc)
|
|||
struct locale *loc;
|
||||
|
||||
test_setup();
|
||||
mt_create_error(21);
|
||||
mt_create_error(36);
|
||||
mt_create_va(mt_new("displayitem", NULL), "weight:int", "item:resource", "description:string", MT_NEW_END);
|
||||
|
||||
loc = get_or_create_locale("de");
|
||||
|
@ -1466,14 +1480,14 @@ static void test_show_without_item(CuTest *tc)
|
|||
locale_setstring(loc, "iteminfo::testitem", "testdescription");
|
||||
|
||||
reshow_cmd(u, ord);
|
||||
CuAssertPtrEquals(tc, 0, test_find_messagetype(f->msgs, "error21"));
|
||||
CuAssertPtrEquals(tc, NULL, test_find_messagetype(f->msgs, "error21"));
|
||||
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error36"));
|
||||
test_clear_messages(f);
|
||||
|
||||
i_add(&(u->items), i_new(itype, 1));
|
||||
reshow_cmd(u, ord);
|
||||
CuAssertPtrEquals(tc, 0, test_find_messagetype(f->msgs, "error21"));
|
||||
CuAssertPtrEquals(tc, 0, test_find_messagetype(f->msgs, "error36"));
|
||||
CuAssertPtrEquals(tc, NULL, test_find_messagetype(f->msgs, "error21"));
|
||||
CuAssertPtrEquals(tc, NULL, test_find_messagetype(f->msgs, "error36"));
|
||||
test_clear_messages(f);
|
||||
|
||||
free_order(ord);
|
||||
|
@ -1488,7 +1502,6 @@ static void test_show_race(CuTest *tc) {
|
|||
message * msg;
|
||||
|
||||
test_setup();
|
||||
|
||||
mt_create_va(mt_new("msg_event", NULL), "string:string", MT_NEW_END);
|
||||
test_create_race("human");
|
||||
rc = test_create_race("elf");
|
||||
|
@ -1504,8 +1517,8 @@ static void test_show_race(CuTest *tc) {
|
|||
|
||||
ord = create_order(K_RESHOW, loc, "Mensch");
|
||||
reshow_cmd(u, ord);
|
||||
CuAssertTrue(tc, test_find_messagetype(u->faction->msgs, "error21") != NULL);
|
||||
CuAssertTrue(tc, test_find_messagetype(u->faction->msgs, "msg_event") == NULL);
|
||||
CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "error21"));
|
||||
CuAssertPtrEquals(tc, NULL, test_find_messagetype(u->faction->msgs, "msg_event"));
|
||||
test_clear_messages(u->faction);
|
||||
free_order(ord);
|
||||
|
||||
|
@ -1618,7 +1631,7 @@ static void test_demon_hunger(CuTest * tc)
|
|||
get_food(r);
|
||||
|
||||
CuAssertIntEquals(tc, 20, i_get(u->items, rtype->itype));
|
||||
CuAssertPtrEquals(tc, 0, test_find_messagetype(f->msgs, "malnourish"));
|
||||
CuAssertPtrEquals(tc, NULL, test_find_messagetype(f->msgs, "malnourish"));
|
||||
|
||||
config_set("hunger.demon.peasant_tolerance", "0");
|
||||
|
||||
|
@ -1759,6 +1772,34 @@ static void test_nmr_timeout(CuTest *tc) {
|
|||
test_teardown();
|
||||
}
|
||||
|
||||
static void test_long_orders(CuTest *tc) {
|
||||
unit *u;
|
||||
|
||||
test_setup();
|
||||
u = test_create_unit(test_create_faction(NULL), test_create_plain(0, 0));
|
||||
CuAssertTrue(tc, long_order_allowed(u));
|
||||
u->flags |= UFL_LONGACTION;
|
||||
CuAssertTrue(tc, !long_order_allowed(u));
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
static void test_long_order_on_ocean(CuTest *tc) {
|
||||
unit *u;
|
||||
race * rc;
|
||||
|
||||
test_setup();
|
||||
rc = test_create_race("pikachu");
|
||||
u = test_create_unit(test_create_faction(rc), test_create_ocean(0, 0));
|
||||
CuAssertTrue(tc, !long_order_allowed(u));
|
||||
rc->flags |= RCF_SWIM;
|
||||
CuAssertTrue(tc, long_order_allowed(u));
|
||||
|
||||
rc = test_create_race("aquarian");
|
||||
u = test_create_unit(test_create_faction(rc), u->region);
|
||||
CuAssertTrue(tc, long_order_allowed(u));
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
CuSuite *get_laws_suite(void)
|
||||
{
|
||||
CuSuite *suite = CuSuiteNew();
|
||||
|
@ -1831,6 +1872,8 @@ CuSuite *get_laws_suite(void)
|
|||
SUITE_ADD_TEST(suite, test_cansee_ring);
|
||||
SUITE_ADD_TEST(suite, test_cansee_sphere);
|
||||
SUITE_ADD_TEST(suite, test_nmr_timeout);
|
||||
SUITE_ADD_TEST(suite, test_long_orders);
|
||||
SUITE_ADD_TEST(suite, test_long_order_on_ocean);
|
||||
|
||||
return suite;
|
||||
}
|
||||
|
|
140
src/lighthouse.c
140
src/lighthouse.c
|
@ -19,72 +19,94 @@ attrib_type at_lighthouse = {
|
|||
/* Rest ist NULL; tempor<6F>res, nicht alterndes Attribut */
|
||||
};
|
||||
|
||||
bool is_lighthouse(const building_type *btype)
|
||||
{
|
||||
return is_building_type(btype, "lighthouse");
|
||||
}
|
||||
|
||||
/* update_lighthouse: call this function whenever the size of a lighthouse changes
|
||||
* it adds temporary markers to the surrounding regions.
|
||||
* The existence of markers says nothing about the quality of the observer in
|
||||
* the lighthouse, for this may change more frequently.
|
||||
*/
|
||||
* it adds temporary markers to the surrounding regions.
|
||||
* The existence of markers says nothing about the quality of the observer in
|
||||
* the lighthouse, since this may change more frequently.
|
||||
*/
|
||||
void update_lighthouse(building * lh)
|
||||
{
|
||||
if (is_building_type(lh->type, "lighthouse")) {
|
||||
region *r = lh->region;
|
||||
region *r = lh->region;
|
||||
assert(is_lighthouse(lh->type));
|
||||
|
||||
r->flags |= RF_LIGHTHOUSE;
|
||||
if (lh->size > 0) {
|
||||
int d = (int)log10(lh->size) + 1;
|
||||
int x;
|
||||
for (x = -d; x <= d; ++x) {
|
||||
int y;
|
||||
for (y = -d; y <= d; ++y) {
|
||||
attrib *a;
|
||||
region *r2;
|
||||
int px = r->x + x, py = r->y + y;
|
||||
r->flags |= RF_LIGHTHOUSE;
|
||||
if (lh->size >= 10) {
|
||||
int d = lighthouse_range(lh);
|
||||
int x;
|
||||
for (x = -d; x <= d; ++x) {
|
||||
int y;
|
||||
for (y = -d; y <= d; ++y) {
|
||||
attrib *a;
|
||||
region *r2;
|
||||
int px = r->x + x, py = r->y + y;
|
||||
|
||||
pnormalize(&px, &py, rplane(r));
|
||||
r2 = findregion(px, py);
|
||||
if (!r2 || !fval(r2->terrain, SEA_REGION))
|
||||
continue;
|
||||
if (distance(r, r2) > d)
|
||||
continue;
|
||||
a = a_find(r2->attribs, &at_lighthouse);
|
||||
while (a && a->type == &at_lighthouse) {
|
||||
building *b = (building *)a->data.v;
|
||||
if (b == lh)
|
||||
break;
|
||||
a = a->next;
|
||||
}
|
||||
if (!a) {
|
||||
a = a_add(&r2->attribs, a_new(&at_lighthouse));
|
||||
a->data.v = (void *)lh;
|
||||
}
|
||||
pnormalize(&px, &py, rplane(r));
|
||||
r2 = findregion(px, py);
|
||||
if (!r2 || !fval(r2->terrain, SEA_REGION))
|
||||
continue;
|
||||
if (distance(r, r2) > d)
|
||||
continue;
|
||||
a = a_find(r2->attribs, &at_lighthouse);
|
||||
while (a && a->type == &at_lighthouse) {
|
||||
building *b = (building *)a->data.v;
|
||||
if (b == lh)
|
||||
break;
|
||||
a = a->next;
|
||||
}
|
||||
if (!a) {
|
||||
a = a_add(&r2->attribs, a_new(&at_lighthouse));
|
||||
a->data.v = (void *)lh;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int lighthouse_range(const building * b, const faction * f, const unit *u)
|
||||
{
|
||||
if (fval(b, BLD_MAINTAINED) && b->size >= 10) {
|
||||
int maxd = (int)log10(b->size) + 1;
|
||||
void remove_lighthouse(const building *lh) {
|
||||
building *b;
|
||||
region * r = lh->region;
|
||||
|
||||
if (u && skill_enabled(SK_PERCEPTION)) {
|
||||
r->flags &= ~RF_LIGHTHOUSE;
|
||||
for (b = r->buildings; b; b = b->next) {
|
||||
if (b != lh && is_lighthouse(b->type)) {
|
||||
update_lighthouse(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int lighthouse_range(const building * b)
|
||||
{
|
||||
if (b->size >= 10 && (b->flags & BLD_MAINTAINED)) {
|
||||
return (int)log10(b->size) + 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lighthouse_view_distance(const building * b, const unit *u)
|
||||
{
|
||||
if (b->size >= 10 && (b->flags & BLD_MAINTAINED)) {
|
||||
int maxd = lighthouse_range(b);
|
||||
|
||||
if (maxd > 0 && u && skill_enabled(SK_PERCEPTION)) {
|
||||
int sk = effskill(u, SK_PERCEPTION, 0) / 3;
|
||||
assert(u->building == b);
|
||||
assert(u->faction == f);
|
||||
if (maxd > sk) maxd = sk;
|
||||
}
|
||||
/* E3A rule: no perception req'd */
|
||||
return maxd;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool check_leuchtturm(region * r, faction * f)
|
||||
bool lighthouse_guarded(const region * r)
|
||||
{
|
||||
attrib *a;
|
||||
|
||||
if (!fval(r->terrain, SEA_REGION)) {
|
||||
if (!r->attribs || !(r->terrain->flags & SEA_REGION)) {
|
||||
return false;
|
||||
}
|
||||
for (a = a_find(r->attribs, &at_lighthouse); a && a->type == &at_lighthouse;
|
||||
|
@ -92,37 +114,11 @@ bool check_leuchtturm(region * r, faction * f)
|
|||
building *b = (building *)a->data.v;
|
||||
|
||||
assert(is_building_type(b->type, "lighthouse"));
|
||||
if (fval(b, BLD_MAINTAINED) && b->size >= 10) {
|
||||
if ((b->flags & BLD_MAINTAINED) && b->size >= 10) {
|
||||
int maxd = (int)log10(b->size) + 1;
|
||||
|
||||
if (skill_enabled(SK_PERCEPTION) && f) {
|
||||
region *r2 = b->region;
|
||||
unit *u;
|
||||
int c = 0;
|
||||
int d = 0;
|
||||
|
||||
for (u = r2->units; u; u = u->next) {
|
||||
if (u->building == b) {
|
||||
c += u->number;
|
||||
if (c > buildingcapacity(b))
|
||||
break;
|
||||
if (u->faction == f) {
|
||||
if (!d)
|
||||
d = distance(r, r2);
|
||||
if (maxd < d)
|
||||
break;
|
||||
if (effskill(u, SK_PERCEPTION, 0) >= d * 3)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (c)
|
||||
break; /* first unit that's no longer in the house ends the search */
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* E3A rule: no perception req'd */
|
||||
return true;
|
||||
}
|
||||
int d = distance(r, b->region);
|
||||
assert(maxd >= d);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -29,15 +29,18 @@ extern "C" {
|
|||
struct faction;
|
||||
struct region;
|
||||
struct building;
|
||||
struct building_type;
|
||||
struct unit;
|
||||
struct attrib;
|
||||
|
||||
extern struct attrib_type at_lighthouse;
|
||||
/* leuchtturm */
|
||||
bool check_leuchtturm(struct region *r, struct faction *f);
|
||||
bool is_lighthouse(const struct building_type *btype);
|
||||
bool lighthouse_guarded(const struct region *r);
|
||||
void update_lighthouse(struct building *b);
|
||||
int lighthouse_range(const struct building *b, const struct faction *f,
|
||||
const struct unit *u);
|
||||
void remove_lighthouse(const struct building *lh);
|
||||
int lighthouse_range(const struct building *b);
|
||||
int lighthouse_view_distance(const struct building *b, const struct unit *u);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -26,35 +26,39 @@ static void test_lighthouse_range(CuTest * tc)
|
|||
u1 = test_create_unit(test_create_faction(NULL), r);
|
||||
u2 = test_create_unit(test_create_faction(NULL), r);
|
||||
b = test_create_building(r, test_create_buildingtype("lighthouse"));
|
||||
CuAssertIntEquals(tc, 0, lighthouse_range(b, NULL, NULL));
|
||||
CuAssertIntEquals(tc, 0, lighthouse_range(b, u1->faction, NULL));
|
||||
CuAssertIntEquals(tc, 0, lighthouse_range(b));
|
||||
b->size = 9;
|
||||
CuAssertIntEquals(tc, 0, lighthouse_range(b));
|
||||
b->size = 10;
|
||||
CuAssertIntEquals(tc, 0, lighthouse_range(b, NULL, NULL));
|
||||
CuAssertIntEquals(tc, 0, lighthouse_range(b));
|
||||
b->flags |= BLD_MAINTAINED;
|
||||
CuAssertIntEquals(tc, 2, lighthouse_range(b));
|
||||
u1->building = b;
|
||||
u2->building = b;
|
||||
u1->number = 10;
|
||||
set_level(u1, SK_PERCEPTION, 3);
|
||||
set_level(u2, SK_PERCEPTION, 3);
|
||||
CuAssertIntEquals(tc, 0, lighthouse_range(b, NULL, NULL));
|
||||
b->flags |= BLD_MAINTAINED;
|
||||
CuAssertIntEquals(tc, 1, lighthouse_range(b, u1->faction, u1));
|
||||
|
||||
CuAssertIntEquals(tc, 1, lighthouse_view_distance(b, u1));
|
||||
set_level(u1, SK_PERCEPTION, 6);
|
||||
CuAssertIntEquals(tc, 2, lighthouse_range(b, u1->faction, u1));
|
||||
/* lighthouse_range does not check inside_building */
|
||||
CuAssertIntEquals(tc, 1, lighthouse_range(b, u2->faction, u2));
|
||||
CuAssertIntEquals(tc, 1, lighthouse_view_distance(b, u2));
|
||||
CuAssertIntEquals(tc, 2, lighthouse_view_distance(b, u1));
|
||||
b->size = 100;
|
||||
update_lighthouse(b);
|
||||
CuAssertIntEquals(tc, 3, lighthouse_range(b, NULL, NULL));
|
||||
CuAssertIntEquals(tc, 2, lighthouse_range(b, u1->faction, u1));
|
||||
CuAssertIntEquals(tc, 3, lighthouse_range(b));
|
||||
CuAssertIntEquals(tc, 2, lighthouse_view_distance(b, u1));
|
||||
set_level(u1, SK_PERCEPTION, 9);
|
||||
CuAssertIntEquals(tc, 3, lighthouse_range(b, u1->faction, u1));
|
||||
CuAssertIntEquals(tc, 1, lighthouse_range(b, u2->faction, u2));
|
||||
CuAssertIntEquals(tc, 3, lighthouse_view_distance(b, u1));
|
||||
CuAssertIntEquals(tc, 1, lighthouse_view_distance(b, u2));
|
||||
b->size = 99;
|
||||
CuAssertIntEquals(tc, 2, lighthouse_view_distance(b, u1));
|
||||
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
static void test_lighthouse_update(CuTest * tc)
|
||||
{
|
||||
region *r1, *r2, *r3;
|
||||
region *r1, *r2, *r3, *r4;
|
||||
building *b;
|
||||
const struct terrain_type *t_ocean, *t_plain;
|
||||
|
||||
|
@ -64,20 +68,23 @@ static void test_lighthouse_update(CuTest * tc)
|
|||
r1 = test_create_region(0, 0, t_plain);
|
||||
r2 = test_create_region(1, 0, t_ocean);
|
||||
r3 = test_create_region(2, 0, t_ocean);
|
||||
r4 = test_create_region(0, 1, t_plain);
|
||||
b = test_create_building(r1, test_create_buildingtype("lighthouse"));
|
||||
b->flags |= BLD_MAINTAINED;
|
||||
CuAssertIntEquals(tc, RF_LIGHTHOUSE, r1->flags&RF_LIGHTHOUSE);
|
||||
CuAssertPtrEquals(tc, NULL, r1->attribs);
|
||||
CuAssertPtrEquals(tc, NULL, r2->attribs);
|
||||
CuAssertPtrEquals(tc, NULL, r3->attribs);
|
||||
CuAssertPtrEquals(tc, NULL, r4->attribs);
|
||||
|
||||
r1->flags = 0;
|
||||
b->size = 1;
|
||||
b->size = 9; /* minimum size for any effect is 10 */
|
||||
update_lighthouse(b);
|
||||
CuAssertIntEquals(tc, RF_LIGHTHOUSE, r1->flags&RF_LIGHTHOUSE);
|
||||
CuAssertPtrNotNull(tc, r2->attribs);
|
||||
CuAssertPtrEquals(tc, (void *)&at_lighthouse, (void *)r2->attribs->type);
|
||||
CuAssertPtrEquals(tc, NULL, r1->attribs);
|
||||
CuAssertPtrEquals(tc, NULL, r2->attribs);
|
||||
CuAssertPtrEquals(tc, NULL, r3->attribs);
|
||||
CuAssertPtrEquals(tc, NULL, r4->attribs);
|
||||
|
||||
a_removeall(&r2->attribs, NULL);
|
||||
r1->flags = 0;
|
||||
|
@ -88,6 +95,39 @@ static void test_lighthouse_update(CuTest * tc)
|
|||
CuAssertPtrEquals(tc, (void *)&at_lighthouse, (void *)r2->attribs->type);
|
||||
CuAssertPtrNotNull(tc, r3->attribs);
|
||||
CuAssertPtrEquals(tc, (void *)&at_lighthouse, (void *)r3->attribs->type);
|
||||
CuAssertPtrEquals(tc, NULL, r4->attribs);
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
static void test_lighthouse_guard(CuTest * tc) {
|
||||
region *r1, *r2, *r3, *r4;
|
||||
building *b;
|
||||
const struct terrain_type *t_ocean, *t_plain;
|
||||
|
||||
test_setup();
|
||||
t_ocean = test_create_terrain("ocean", SEA_REGION);
|
||||
t_plain = test_create_terrain("plain", LAND_REGION);
|
||||
r1 = test_create_region(0, 0, t_plain);
|
||||
r2 = test_create_region(1, 0, t_ocean);
|
||||
r3 = test_create_region(2, 0, t_ocean);
|
||||
r4 = test_create_region(0, 1, t_plain);
|
||||
b = test_create_building(r1, test_create_buildingtype("lighthouse"));
|
||||
b->flags |= BLD_MAINTAINED;
|
||||
b->size = 10;
|
||||
CuAssertIntEquals(tc, 2, lighthouse_range(b));
|
||||
update_lighthouse(b);
|
||||
CuAssertIntEquals(tc, RF_LIGHTHOUSE, r1->flags&RF_LIGHTHOUSE);
|
||||
CuAssertPtrEquals(tc, NULL, r1->attribs);
|
||||
CuAssertPtrEquals(tc, (void *)&at_lighthouse, (void *)r2->attribs->type);
|
||||
CuAssertPtrEquals(tc, (void *)&at_lighthouse, (void *)r3->attribs->type);
|
||||
CuAssertPtrEquals(tc, NULL, r4->attribs);
|
||||
CuAssertIntEquals(tc, false, lighthouse_guarded(r1));
|
||||
CuAssertIntEquals(tc, true, lighthouse_guarded(r2));
|
||||
CuAssertIntEquals(tc, true, lighthouse_guarded(r3));
|
||||
CuAssertIntEquals(tc, false, lighthouse_guarded(r4));
|
||||
b->size = 1; /* size can go down in destroy_cmd */
|
||||
CuAssertIntEquals(tc, false, lighthouse_guarded(r2));
|
||||
CuAssertIntEquals(tc, false, lighthouse_guarded(r3));
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
|
@ -96,5 +136,6 @@ CuSuite *get_lighthouse_suite(void)
|
|||
CuSuite *suite = CuSuiteNew();
|
||||
SUITE_ADD_TEST(suite, test_lighthouse_range);
|
||||
SUITE_ADD_TEST(suite, test_lighthouse_update);
|
||||
SUITE_ADD_TEST(suite, test_lighthouse_guard);
|
||||
return suite;
|
||||
}
|
||||
|
|
|
@ -2949,7 +2949,7 @@ void free_spellbook(spellbook *sb) {
|
|||
free(sb);
|
||||
}
|
||||
|
||||
static int free_spellbook_cb(const void *match, const void *key, size_t keylen, void *data) {
|
||||
static int free_spellbook_cb(void *match, const void *key, size_t keylen, void *data) {
|
||||
const sb_entry *ent = (const sb_entry *)match;
|
||||
UNUSED_ARG(data);
|
||||
UNUSED_ARG(keylen);
|
||||
|
|
|
@ -334,6 +334,8 @@ int main(int argc, char **argv)
|
|||
game_done();
|
||||
lua_done(L);
|
||||
log_close();
|
||||
stats_write(stdout, "");
|
||||
stats_close();
|
||||
if (d) {
|
||||
iniparser_freedict(d);
|
||||
}
|
||||
|
|
100
src/monsters.c
100
src/monsters.c
|
@ -24,7 +24,6 @@
|
|||
#include "monsters.h"
|
||||
|
||||
#include "economy.h"
|
||||
#include "chaos.h"
|
||||
#include "give.h"
|
||||
#include "guard.h"
|
||||
#include "laws.h"
|
||||
|
@ -556,7 +555,7 @@ static order *monster_learn(unit * u)
|
|||
const struct locale *lang = u->faction->locale;
|
||||
|
||||
/* can these monsters even study? */
|
||||
if (!unit_can_study(u)) {
|
||||
if (!check_student(u, NULL, SK_PERCEPTION)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -607,6 +606,7 @@ static void recruit_dracoids(unit * dragon, int size)
|
|||
region *r = dragon->region;
|
||||
const struct item *weapon = NULL;
|
||||
unit *un = create_unit(r, f, size, get_race(RC_DRACOID), 0, NULL, NULL);
|
||||
stats_count("monsters.create.dracoid", 1);
|
||||
|
||||
fset(un, UFL_ISNEW | UFL_MOVED);
|
||||
|
||||
|
@ -756,6 +756,11 @@ void plan_monsters(faction * f)
|
|||
if (u->faction!=f)
|
||||
continue;
|
||||
|
||||
/* Parteitarnung von Monstern ist doof: */
|
||||
if (fval(u, UFL_ANON_FACTION)) {
|
||||
u->flags &= ~UFL_ANON_FACTION;
|
||||
}
|
||||
|
||||
/* Befehle m<>ssen jede Runde neu gegeben werden: */
|
||||
free_orders(&u->orders);
|
||||
if (skill_enabled(SK_PERCEPTION)) {
|
||||
|
@ -823,7 +828,7 @@ void plan_monsters(faction * f)
|
|||
}
|
||||
}
|
||||
}
|
||||
if (long_order == NULL && unit_can_study(u)) {
|
||||
if (long_order == NULL && check_student(u, NULL, SK_WEAPONLESS)) {
|
||||
/* Einheiten, die Waffenlosen Kampf lernen k<>nnten, lernen es um
|
||||
* zu bewachen: */
|
||||
if (rc->bonus[SK_WEAPONLESS] != -99) {
|
||||
|
@ -843,18 +848,14 @@ void plan_monsters(faction * f)
|
|||
pathfinder_cleanup();
|
||||
}
|
||||
|
||||
static double chaosfactor(region * r)
|
||||
{
|
||||
return fval(r, RF_CHAOTIC) ? ((double)(1 + get_chaoscount(r)) / 1000.0) : 0.0;
|
||||
}
|
||||
|
||||
static int nrand(int handle_start, int sub)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
do {
|
||||
if (rng_int() % 100 < handle_start)
|
||||
if (rng_int() % 100 < handle_start) {
|
||||
res++;
|
||||
}
|
||||
handle_start -= sub;
|
||||
} while (handle_start > 0);
|
||||
|
||||
|
@ -863,6 +864,7 @@ static int nrand(int handle_start, int sub)
|
|||
|
||||
unit *spawn_seaserpent(region *r, faction *f) {
|
||||
unit *u = create_unit(r, f, 1, get_race(RC_SEASERPENT), 0, NULL, NULL);
|
||||
stats_count("monsters.create.seaserpent", 1);
|
||||
fset(u, UFL_ISNEW | UFL_MOVED);
|
||||
equip_unit(u, "seed_seaserpent");
|
||||
return u;
|
||||
|
@ -876,7 +878,7 @@ void spawn_dragons(void)
|
|||
region *r;
|
||||
faction *monsters = get_or_create_monsters();
|
||||
int minage = config_get_int("monsters.spawn.min_age", 100);
|
||||
int spawn_chance = 100 * config_get_int("monsters.spawn.chance", 100);
|
||||
int spawn_chance = config_get_int("monsters.spawn.chance", 100) * 100;
|
||||
|
||||
if (spawn_chance <= 0) {
|
||||
/* monster spawning disabled */
|
||||
|
@ -895,19 +897,21 @@ void spawn_dragons(void)
|
|||
else if ((r->terrain == newterrain(T_GLACIER)
|
||||
|| r->terrain == newterrain(T_SWAMP)
|
||||
|| r->terrain == newterrain(T_DESERT))
|
||||
&& rng_int() % spawn_chance < (5 + 100 * chaosfactor(r))) {
|
||||
&& rng_int() % spawn_chance < 6)
|
||||
{
|
||||
if (chance(0.80)) {
|
||||
u = create_unit(r, monsters, nrand(60, 20) + 1, get_race(RC_FIREDRAGON), 0, NULL, NULL);
|
||||
}
|
||||
else {
|
||||
u = create_unit(r, monsters, nrand(30, 20) + 1, get_race(RC_DRAGON), 0, NULL, NULL);
|
||||
}
|
||||
stats_count("monsters.create.dragon", 1);
|
||||
fset(u, UFL_ISNEW | UFL_MOVED);
|
||||
equip_unit(u, "seed_dragon");
|
||||
|
||||
log_debug("spawning %d %s in %s.\n", u->number,
|
||||
LOC(default_locale,
|
||||
rc_name_s(u_race(u), (u->number == 1) ? NAME_SINGULAR : NAME_PLURAL)), regionname(r, NULL));
|
||||
rc_name_s(u_race(u), (u->number == 1) ? NAME_SINGULAR : NAME_PLURAL)), regionname(r, NULL));
|
||||
|
||||
name_unit(u);
|
||||
|
||||
|
@ -932,9 +936,9 @@ void spawn_undead(void)
|
|||
continue;
|
||||
}
|
||||
}
|
||||
/* Chance 0.1% * chaosfactor */
|
||||
|
||||
if (r->land && unburied > rpeasants(r) / 20
|
||||
&& rng_int() % 10000 < (100 + 100 * chaosfactor(r))) {
|
||||
&& rng_int() % 10000 < 100) {
|
||||
message *msg;
|
||||
unit *u;
|
||||
/* es ist sinnfrei, wenn irgendwo im Wald 3er-Einheiten Untote entstehen.
|
||||
|
@ -962,6 +966,7 @@ void spawn_undead(void)
|
|||
}
|
||||
|
||||
u = create_unit(r, monsters, undead, rc, 0, NULL, NULL);
|
||||
stats_count("monsters.create.undead", 1);
|
||||
fset(u, UFL_ISNEW | UFL_MOVED);
|
||||
if ((rc == get_race(RC_SKELETON) || rc == get_race(RC_ZOMBIE))
|
||||
&& rng_int() % 10 < 4) {
|
||||
|
@ -1015,37 +1020,42 @@ static void eaten_by_monster(unit * u)
|
|||
{
|
||||
/* adjustment for smaller worlds */
|
||||
double multi = RESOURCE_QUANTITY * newterrain(T_PLAIN)->size / 10000.0;
|
||||
int n = 0;
|
||||
int horse = -1;
|
||||
const resource_type *rhorse = get_resourcetype(R_HORSE);
|
||||
const race *rc = u_race(u);
|
||||
int scare;
|
||||
int p = rpeasants(u->region);
|
||||
|
||||
scare = rc_scare(rc);
|
||||
if (scare>0) {
|
||||
n = rng_int() % scare * u->number;
|
||||
} else {
|
||||
n = rng_int() % (u->number / 20 + 1);
|
||||
horse = 0;
|
||||
}
|
||||
horse = horse ? i_get(u->items, rhorse->itype) : 0;
|
||||
if (p > 0) {
|
||||
int horse = -1;
|
||||
int scare = rc_scare(rc);
|
||||
int n = 0;
|
||||
|
||||
n = (int)(n * multi);
|
||||
if (n > 0) {
|
||||
|
||||
n = lovar(n);
|
||||
|
||||
if (n > 0) {
|
||||
int p = rpeasants(u->region);
|
||||
if (p < n) n = p;
|
||||
deathcounts(u->region, n);
|
||||
rsetpeasants(u->region, rpeasants(u->region) - n);
|
||||
ADDMSG(&u->region->msgs, msg_message("eatpeasants", "unit amount", u, n));
|
||||
if (scare > 0) {
|
||||
n = rng_int() % scare * u->number;
|
||||
}
|
||||
else {
|
||||
n = rng_int() % (u->number / 20 + 1);
|
||||
horse = 0;
|
||||
}
|
||||
|
||||
horse = horse ? i_get(u->items, rhorse->itype) : 0;
|
||||
if (horse > 0) {
|
||||
i_change(&u->items, rhorse->itype, -horse);
|
||||
ADDMSG(&u->region->msgs, msg_message("eathorse", "unit amount", u, horse));
|
||||
}
|
||||
|
||||
n = (int)(n * multi);
|
||||
if (n > 0) {
|
||||
n = lovar(n);
|
||||
|
||||
if (p < n) n = p;
|
||||
if (n > 0) {
|
||||
if (n > 0) {
|
||||
deathcounts(u->region, n);
|
||||
rsetpeasants(u->region, rpeasants(u->region) - n);
|
||||
ADDMSG(&u->region->msgs, msg_message("eatpeasants", "unit amount", u, n));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (horse > 0) {
|
||||
i_change(&u->items, rhorse->itype, -horse);
|
||||
ADDMSG(&u->region->msgs, msg_message("eathorse", "unit amount", u, horse));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1058,10 +1068,12 @@ static void absorbed_by_monster(unit * u)
|
|||
if (n > 0) {
|
||||
int p = rpeasants(u->region);
|
||||
if (p < n) n = p;
|
||||
rsetpeasants(u->region, rpeasants(u->region) - n);
|
||||
scale_number(u, u->number + n);
|
||||
ADDMSG(&u->region->msgs, msg_message("absorbpeasants",
|
||||
"unit race amount", u, u_race(u), n));
|
||||
if (n > 0) {
|
||||
rsetpeasants(u->region, rpeasants(u->region) - n);
|
||||
scale_number(u, u->number + n);
|
||||
ADDMSG(&u->region->msgs, msg_message("absorbpeasants",
|
||||
"unit race amount", u, u_race(u), n));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
134
src/move.c
134
src/move.c
|
@ -47,6 +47,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
#include "laws.h"
|
||||
#include "reports.h"
|
||||
#include "study.h"
|
||||
#include "spy.h"
|
||||
#include "alchemy.h"
|
||||
#include "travelthru.h"
|
||||
#include "vortex.h"
|
||||
|
@ -73,7 +74,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
#include <util/assert.h>
|
||||
#include <util/attrib.h>
|
||||
#include <util/base36.h>
|
||||
#include <util/bsdstring.h>
|
||||
#include <util/gamedata.h>
|
||||
#include <util/language.h>
|
||||
#include <util/lists.h>
|
||||
|
@ -542,6 +542,7 @@ static ship *do_maelstrom(region * r, unit * u)
|
|||
if (sh->damage >= sh->size * DAMAGE_SCALE) {
|
||||
ADDMSG(&u->faction->msgs, msg_message("entermaelstrom",
|
||||
"region ship damage sink", r, sh, damage, 1));
|
||||
sink_ship(sh);
|
||||
remove_ship(&sh->region->ships, sh);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -629,7 +630,7 @@ mark_travelthru(unit * u, region * r, const region_list * route,
|
|||
}
|
||||
}
|
||||
|
||||
ship *move_ship(ship * sh, region * from, region * to, region_list * route)
|
||||
void move_ship(ship * sh, region * from, region * to, region_list * route)
|
||||
{
|
||||
unit **iunit = &from->units;
|
||||
unit **ulist = &to->units;
|
||||
|
@ -662,8 +663,6 @@ ship *move_ship(ship * sh, region * from, region * to, region_list * route)
|
|||
if (*iunit == u)
|
||||
iunit = &u->next;
|
||||
}
|
||||
|
||||
return sh;
|
||||
}
|
||||
|
||||
static bool is_freezing(const unit * u)
|
||||
|
@ -856,39 +855,36 @@ static void drifting_ships(region * r)
|
|||
}
|
||||
}
|
||||
|
||||
if (rnext != NULL) {
|
||||
if (rnext && firstu) {
|
||||
message *msg = msg_message("ship_drift", "ship dir", sh, dir);
|
||||
msg_to_ship_inmates(sh, &firstu, &lastu, msg);
|
||||
}
|
||||
|
||||
fset(sh, SF_DRIFTED);
|
||||
if (ovl >= overload_start()) {
|
||||
damage_ship(sh, damage_overload(ovl));
|
||||
msg_to_ship_inmates(sh, &firstu, &lastu, msg_message("massive_overload", "ship", sh));
|
||||
}
|
||||
else {
|
||||
damage_ship(sh, damage_drift);
|
||||
}
|
||||
if (sh->damage >= sh->size * DAMAGE_SCALE) {
|
||||
msg_to_ship_inmates(sh, &firstu, &lastu, msg_message("shipsink", "ship", sh));
|
||||
sink_ship(sh);
|
||||
remove_ship(shp, sh);
|
||||
}
|
||||
else if (rnext) {
|
||||
/* Das Schiff und alle Einheiten darin werden nun von r
|
||||
* nach rnext verschoben. Danach eine Meldung. */
|
||||
* nach rnext verschoben. Danach eine Meldung. */
|
||||
add_regionlist(&route, rnext);
|
||||
|
||||
set_coast(sh, r, rnext);
|
||||
sh = move_ship(sh, r, rnext, route);
|
||||
move_ship(sh, r, rnext, route);
|
||||
free_regionlist(route);
|
||||
|
||||
if (firstu != NULL) {
|
||||
message *msg = msg_message("ship_drift", "ship dir", sh, dir);
|
||||
msg_to_ship_inmates(sh, &firstu, &lastu, msg);
|
||||
}
|
||||
}
|
||||
|
||||
if (sh != NULL) {
|
||||
fset(sh, SF_DRIFTED);
|
||||
if (ovl >= overload_start()) {
|
||||
damage_ship(sh, damage_overload(ovl));
|
||||
msg_to_ship_inmates(sh, &firstu, &lastu, msg_message("massive_overload", "ship", sh));
|
||||
}
|
||||
else {
|
||||
damage_ship(sh, damage_drift);
|
||||
}
|
||||
if (sh->damage >= sh->size * DAMAGE_SCALE) {
|
||||
msg_to_ship_inmates(sh, &firstu, &lastu, msg_message("shipsink", "ship", sh));
|
||||
remove_ship(&sh->region->ships, sh);
|
||||
}
|
||||
}
|
||||
|
||||
if (*shp == sh)
|
||||
else {
|
||||
shp = &sh->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1047,15 +1043,17 @@ int movewhere(const unit * u, const char *token, region * r, region ** resultp)
|
|||
order * cycle_route(order * ord, const struct locale *lang, int gereist)
|
||||
{
|
||||
int cm = 0;
|
||||
char tail[1024], *bufp = tail;
|
||||
char neworder[2048], *obuf = neworder;
|
||||
char tail[1024];
|
||||
char neworder[2048];
|
||||
char token[128];
|
||||
direction_t d = NODIRECTION;
|
||||
bool paused = false;
|
||||
bool pause;
|
||||
order *norder;
|
||||
size_t size = sizeof(tail) - 1;
|
||||
sbstring sbtail;
|
||||
sbstring sborder;
|
||||
|
||||
sbs_init(&sbtail, tail, sizeof(tail));
|
||||
sbs_init(&sborder, neworder, sizeof(neworder));
|
||||
assert(getkeyword(ord) == K_ROUTE);
|
||||
tail[0] = '\0';
|
||||
neworder[0] = '\0';
|
||||
|
@ -1063,14 +1061,10 @@ order * cycle_route(order * ord, const struct locale *lang, int gereist)
|
|||
|
||||
for (cm = 0;; ++cm) {
|
||||
const char *s;
|
||||
pause = false;
|
||||
s = gettoken(token, sizeof(token));
|
||||
if (s && *s) {
|
||||
d = get_direction(s, lang);
|
||||
if (d == D_PAUSE) {
|
||||
pause = true;
|
||||
}
|
||||
else if (d == NODIRECTION) {
|
||||
if (d == NODIRECTION) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1079,38 +1073,37 @@ order * cycle_route(order * ord, const struct locale *lang, int gereist)
|
|||
}
|
||||
if (cm < gereist) {
|
||||
/* TODO: hier sollte keine PAUSE auftreten */
|
||||
assert(!pause);
|
||||
if (!pause) {
|
||||
assert (d != D_PAUSE);
|
||||
if (d != D_PAUSE) {
|
||||
const char *loc = LOC(lang, shortdirections[d]);
|
||||
assert(loc);
|
||||
if (bufp != tail) {
|
||||
bufp = STRLCPY_EX(bufp, " ", &size, "cycle_route");
|
||||
if (sbs_length(&sbtail) > 0) {
|
||||
sbs_strcat(&sbtail, " ");
|
||||
}
|
||||
bufp = STRLCPY_EX(bufp, loc, &size, "cycle_route");
|
||||
sbs_strcat(&sbtail, loc);
|
||||
}
|
||||
}
|
||||
else if (strlen(neworder) > sizeof(neworder) / 2)
|
||||
break;
|
||||
else if (cm == gereist && !paused && pause) {
|
||||
else if (cm == gereist && !paused && (d == D_PAUSE)) {
|
||||
const char *loc = LOC(lang, parameters[P_PAUSE]);
|
||||
bufp = STRLCPY_EX(bufp, " ", &size, "cycle_route");
|
||||
bufp = STRLCPY_EX(bufp, loc, &size, "cycle_route");
|
||||
sbs_strcat(&sbtail, " ");
|
||||
sbs_strcat(&sbtail, loc);
|
||||
paused = true;
|
||||
}
|
||||
else if (pause) {
|
||||
/* da PAUSE nicht in ein shortdirections[d] umgesetzt wird (ist
|
||||
* hier keine normale direction), muss jede PAUSE einzeln
|
||||
* herausgefiltert und explizit gesetzt werden */
|
||||
if (neworder != obuf) {
|
||||
obuf += str_strlcat(obuf, " ", sizeof(neworder) - (obuf - neworder));
|
||||
}
|
||||
obuf += str_strlcat(obuf, LOC(lang, parameters[P_PAUSE]), sizeof(neworder) - (obuf - neworder));
|
||||
}
|
||||
else {
|
||||
if (neworder != obuf) {
|
||||
obuf += str_strlcat(obuf, " ", sizeof(neworder) - (obuf - neworder));
|
||||
if (sbs_length(&sbtail) > 0) {
|
||||
sbs_strcat(&sborder, " ");
|
||||
}
|
||||
if (d == D_PAUSE) {
|
||||
/* da PAUSE nicht in ein shortdirections[d] umgesetzt wird (ist
|
||||
* hier keine normale direction), muss jede PAUSE einzeln
|
||||
* herausgefiltert und explizit gesetzt werden */
|
||||
sbs_strcat(&sborder, LOC(lang, parameters[P_PAUSE]));
|
||||
}
|
||||
else {
|
||||
sbs_strcat(&sborder, LOC(lang, shortdirections[d]));
|
||||
}
|
||||
obuf += str_strlcat(obuf, LOC(lang, shortdirections[d]), sizeof(neworder) - (obuf - neworder));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1783,7 +1776,7 @@ static void sail(unit * u, order * ord, region_list ** routep, bool drifting)
|
|||
|
||||
/* storms should be the first thing we do. */
|
||||
stormchance = stormyness / shipspeed(sh, u);
|
||||
if (check_leuchtturm(next_point, NULL)) {
|
||||
if (lighthouse_guarded(next_point)) {
|
||||
if (lighthouse_div > 0) {
|
||||
stormchance /= lighthouse_div;
|
||||
}
|
||||
|
@ -1871,7 +1864,7 @@ static void sail(unit * u, order * ord, region_list ** routep, bool drifting)
|
|||
if (reason == SA_NO_INSECT) {
|
||||
ADDMSG(&f->msgs, msg_message("detectforbidden", "unit region", u, sh->region));
|
||||
}
|
||||
else if (check_leuchtturm(current_point, NULL)) {
|
||||
else if (lighthouse_guarded(current_point)) {
|
||||
ADDMSG(&f->msgs, msg_message("sailnolandingstorm", "ship region", sh, next_point));
|
||||
}
|
||||
else {
|
||||
|
@ -1930,6 +1923,7 @@ static void sail(unit * u, order * ord, region_list ** routep, bool drifting)
|
|||
if (sh->damage >= sh->size * DAMAGE_SCALE) {
|
||||
if (sh->region) {
|
||||
ADDMSG(&f->msgs, msg_message("shipsink", "ship", sh));
|
||||
sink_ship(sh);
|
||||
remove_ship(&sh->region->ships, sh);
|
||||
}
|
||||
sh = NULL;
|
||||
|
@ -1969,7 +1963,7 @@ static void sail(unit * u, order * ord, region_list ** routep, bool drifting)
|
|||
if (fval(u, UFL_FOLLOWING))
|
||||
caught_target(current_point, u);
|
||||
|
||||
sh = move_ship(sh, starting_point, current_point, *routep);
|
||||
move_ship(sh, starting_point, current_point, *routep);
|
||||
|
||||
/* Hafengebühren ? */
|
||||
|
||||
|
@ -2250,10 +2244,9 @@ static direction_t hunted_dir(attrib * at, int id)
|
|||
int follow_ship(unit * u, order * ord)
|
||||
{
|
||||
region *rc = u->region;
|
||||
size_t bytes;
|
||||
sbstring sbcmd;
|
||||
int moves, id, speed;
|
||||
char command[256], *bufp = command;
|
||||
size_t size = sizeof(command);
|
||||
char command[256];
|
||||
direction_t dir;
|
||||
|
||||
if (fval(u, UFL_NOTMOVING)) {
|
||||
|
@ -2289,11 +2282,10 @@ int follow_ship(unit * u, order * ord)
|
|||
return 0;
|
||||
}
|
||||
|
||||
bufp = command;
|
||||
bytes = slprintf(bufp, size, "%s %s", LOC(u->faction->locale, keyword(K_MOVE)), LOC(u->faction->locale, directions[dir]));
|
||||
assert(bytes <= INT_MAX);
|
||||
if (wrptr(&bufp, &size, (int)bytes) != 0)
|
||||
WARN_STATIC_BUFFER();
|
||||
sbs_init(&sbcmd, command, sizeof(command));
|
||||
sbs_strcpy(&sbcmd, LOC(u->faction->locale, keyword(K_MOVE)));
|
||||
sbs_strcat(&sbcmd, " ");
|
||||
sbs_strcat(&sbcmd, LOC(u->faction->locale, directions[dir]));
|
||||
|
||||
moves = 1;
|
||||
|
||||
|
@ -2309,8 +2301,8 @@ int follow_ship(unit * u, order * ord)
|
|||
rc = rconnect(rc, dir);
|
||||
while (rc && moves < speed && (dir = hunted_dir(rc->attribs, id)) != NODIRECTION) {
|
||||
const char *loc = LOC(u->faction->locale, directions[dir]);
|
||||
bufp = STRLCPY_EX(bufp, " ", &size, "hunt");
|
||||
bufp = STRLCPY_EX(bufp, loc, &size, "hunt");
|
||||
sbs_strcat(&sbcmd, " ");
|
||||
sbs_strcat(&sbcmd, loc);
|
||||
moves++;
|
||||
rc = rconnect(rc, dir);
|
||||
}
|
||||
|
|
|
@ -77,7 +77,7 @@ extern "C" {
|
|||
bool canfly(struct unit *u);
|
||||
void leave_trail(struct ship *sh, struct region *from,
|
||||
struct region_list *route);
|
||||
struct ship *move_ship(struct ship *sh, struct region *from,
|
||||
void move_ship(struct ship *sh, struct region *from,
|
||||
struct region *to, struct region_list *route);
|
||||
int walkingcapacity(const struct unit *u);
|
||||
int movement_speed(const struct unit * u);
|
||||
|
|
|
@ -287,6 +287,9 @@ void setup_drift (struct drift_fixture *fix) {
|
|||
u_set_ship(fix->u, fix->sh = test_create_ship(fix->u->region, fix->st_boat));
|
||||
assert(fix->sh);
|
||||
|
||||
mt_create_va(mt_new("sink_msg", NULL),
|
||||
"ship:ship", "region:region", MT_NEW_END);
|
||||
|
||||
mt_create_va(mt_new("ship_drift", NULL),
|
||||
"ship:ship", "dir:int", MT_NEW_END);
|
||||
mt_create_va(mt_new("shipsink", NULL),
|
||||
|
@ -495,6 +498,7 @@ static void test_follow_ship_msg(CuTest * tc) {
|
|||
|
||||
follow_ship(u, ord);
|
||||
|
||||
CuAssertPtrEquals(tc, r, u->region);
|
||||
CuAssertPtrNotNull(tc, msg = test_find_messagetype(u->faction->msgs, "error18"));
|
||||
p = msg->parameters[2].v;
|
||||
CuAssertPtrNotNull(tc, p);
|
||||
|
|
|
@ -30,6 +30,8 @@ static void setup_piracy(void) {
|
|||
st_boat = test_create_shiptype("boat");
|
||||
st_boat->cargo = 1000;
|
||||
|
||||
mt_create_error(144);
|
||||
mt_create_error(146);
|
||||
mt_create_va(mt_new("piratenovictim", NULL),
|
||||
"ship:ship", "unit:unit", "region:region", MT_NEW_END);
|
||||
mt_create_va(mt_new("piratesawvictim", NULL),
|
||||
|
|
|
@ -26,6 +26,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
#include "economy.h"
|
||||
#include "monsters.h"
|
||||
#include "move.h"
|
||||
#include "spy.h"
|
||||
#include "study.h"
|
||||
#include "volcano.h"
|
||||
|
||||
|
@ -295,6 +296,7 @@ static void move_iceberg(region * r)
|
|||
ADDMSG(&u->faction->msgs, msg_message("overrun_by_iceberg_des",
|
||||
"ship", sh));
|
||||
}
|
||||
sink_ship(sh);
|
||||
remove_ship(&sh->region->ships, sh);
|
||||
}
|
||||
else if (u != NULL) {
|
||||
|
@ -421,6 +423,7 @@ static void godcurse(void)
|
|||
ADDMSG(&uo->faction->msgs,
|
||||
msg_message("godcurse_destroy_ship", "ship", sh));
|
||||
}
|
||||
sink_ship(sh);
|
||||
remove_ship(&sh->region->ships, sh);
|
||||
}
|
||||
sh = shn;
|
||||
|
|
|
@ -14,12 +14,19 @@
|
|||
#include <stddef.h>
|
||||
#include <CuTest.h>
|
||||
|
||||
static void setup_renumber(CuTest *tc) {
|
||||
test_setup_ex(tc);
|
||||
mt_create_error(114);
|
||||
mt_create_error(115);
|
||||
mt_create_error(116);
|
||||
}
|
||||
|
||||
static void test_renumber_faction(CuTest *tc) {
|
||||
unit *u;
|
||||
int uno, no;
|
||||
const struct locale *lang;
|
||||
|
||||
test_setup_ex(tc);
|
||||
setup_renumber(tc);
|
||||
u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL));
|
||||
no = u->faction->no;
|
||||
uno = (no > 1) ? no - 1 : no + 1;
|
||||
|
@ -37,7 +44,7 @@ static void test_renumber_faction_duplicate(CuTest *tc) {
|
|||
int no;
|
||||
const struct locale *lang;
|
||||
|
||||
test_setup_ex(tc);
|
||||
setup_renumber(tc);
|
||||
mt_create_va(mt_new("renumber_inuse", NULL), "id:int", MT_NEW_END);
|
||||
f2 = test_create_faction(NULL);
|
||||
u = test_create_unit(f = test_create_faction(NULL), test_create_region(0, 0, NULL));
|
||||
|
@ -57,7 +64,7 @@ static void test_renumber_faction_invalid(CuTest *tc) {
|
|||
int no;
|
||||
const struct locale *lang;
|
||||
|
||||
test_setup_ex(tc);
|
||||
setup_renumber(tc);
|
||||
u = test_create_unit(f = test_create_faction(0), test_create_region(0, 0, 0));
|
||||
no = f->no;
|
||||
lang = f->locale;
|
||||
|
@ -87,7 +94,7 @@ static void test_renumber_building(CuTest *tc) {
|
|||
int uno, no;
|
||||
const struct locale *lang;
|
||||
|
||||
test_setup_ex(tc);
|
||||
setup_renumber(tc);
|
||||
u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL));
|
||||
u->building = test_create_building(u->region, NULL);
|
||||
no = u->building->no;
|
||||
|
@ -105,7 +112,7 @@ static void test_renumber_building_duplicate(CuTest *tc) {
|
|||
int uno, no;
|
||||
const struct locale *lang;
|
||||
|
||||
test_setup_ex(tc);
|
||||
setup_renumber(tc);
|
||||
u = test_create_unit(f = test_create_faction(NULL), test_create_region(0, 0, NULL));
|
||||
u->building = test_create_building(u->region, NULL);
|
||||
uno = u->building->no;
|
||||
|
@ -124,7 +131,7 @@ static void test_renumber_ship(CuTest *tc) {
|
|||
int uno, no;
|
||||
const struct locale *lang;
|
||||
|
||||
test_setup_ex(tc);
|
||||
setup_renumber(tc);
|
||||
u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL));
|
||||
u->ship = test_create_ship(u->region, NULL);
|
||||
no = u->ship->no;
|
||||
|
@ -141,7 +148,7 @@ static void test_renumber_ship_twice(CuTest *tc) {
|
|||
int uno, no;
|
||||
const struct locale *lang;
|
||||
|
||||
test_setup_ex(tc);
|
||||
setup_renumber(tc);
|
||||
u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL));
|
||||
u->ship = test_create_ship(u->region, NULL);
|
||||
no = u->ship->no;
|
||||
|
@ -163,7 +170,7 @@ static void test_renumber_ship_duplicate(CuTest *tc) {
|
|||
int uno, no;
|
||||
const struct locale *lang;
|
||||
|
||||
test_setup_ex(tc);
|
||||
setup_renumber(tc);
|
||||
u = test_create_unit(f = test_create_faction(NULL), test_create_region(0, 0, NULL));
|
||||
u->ship = test_create_ship(u->region, NULL);
|
||||
uno = u->ship->no;
|
||||
|
@ -182,7 +189,7 @@ static void test_renumber_unit(CuTest *tc) {
|
|||
int uno, no;
|
||||
const struct locale *lang;
|
||||
|
||||
test_setup_ex(tc);
|
||||
setup_renumber(tc);
|
||||
u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL));
|
||||
no = u->no;
|
||||
uno = (no > 1) ? no - 1 : no + 1;
|
||||
|
@ -200,7 +207,7 @@ static void test_renumber_unit_duplicate(CuTest *tc) {
|
|||
int no;
|
||||
const struct locale *lang;
|
||||
|
||||
test_setup_ex(tc);
|
||||
setup_renumber(tc);
|
||||
u = test_create_unit(f = test_create_faction(NULL), test_create_region(0, 0, NULL));
|
||||
no = u->no;
|
||||
u2 = test_create_unit(f, u->region);
|
||||
|
@ -219,7 +226,7 @@ static void test_renumber_unit_limit(CuTest *tc) {
|
|||
int no;
|
||||
const struct locale *lang;
|
||||
|
||||
test_setup_ex(tc);
|
||||
setup_renumber(tc);
|
||||
u = test_create_unit(f = test_create_faction(NULL), test_create_region(0, 0, NULL));
|
||||
no = u->no;
|
||||
lang = f->locale;
|
||||
|
@ -237,7 +244,7 @@ static void test_renumber_unit_invalid(CuTest *tc) {
|
|||
int no;
|
||||
const struct locale *lang;
|
||||
|
||||
test_setup_ex(tc);
|
||||
setup_renumber(tc);
|
||||
u = test_create_unit(f = test_create_faction(NULL), test_create_region(0, 0, NULL));
|
||||
no = u->no;
|
||||
lang = f->locale;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue