forked from github/server
commit
c3992c6a6e
140 changed files with 2712 additions and 1953 deletions
clibs
conf
process
res
core
e3a
eressea
s
scripts
eressea
tests
src
CMakeLists.txtacademy.c
attributes
battle.cbind_eressea.cbind_unit.cbuilding_action.ccreport.ceconomy.ceressea.cgive.chelpers.citems.citems
kernel
ally.cally.hbuild.cbuilding.cbuilding.hconnection.ccurse.ccurse.hequipment.cequipment.hequipment.test.cfaction.cfaction.hgroup.citem.citem.test.cmessages.cmessages.hmessages.test.corder.corder.horder.test.cplane.cplane.hrace.crace.hregion.cregion.hregion.test.csave.csave.hsave.test.cunit.cunit.hunit.test.cversion.cxmlreader.c
keyword.claws.claws.hlaws.test.cmagic.cmagic.hmagic.test.cmodules
monsters.cmonsters.test.cmove.cmove.hmove.test.corderfile.corderfile.horderfile.test.c
2
clibs
2
clibs
|
@ -1 +1 @@
|
|||
Subproject commit d286006a28c8aa7cd70ed7fd4cd172b50ade9727
|
||||
Subproject commit 147584ad70b220abf6a4e97ca76e785729b9ac32
|
|
@ -27,7 +27,7 @@
|
|||
"rules.reserve.twophase": true,
|
||||
"rules.give.max_men": -1,
|
||||
"rules.check_overload": false,
|
||||
"rules.limit.faction": 3000,
|
||||
"rules.limit.faction": 2500,
|
||||
"rules.maxskills.magic": 5,
|
||||
"rules.guard.base_stop_prob": 0.30,
|
||||
"rules.guard.skill_stop_prob": 0.05,
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
<item name="log" amount="10"/>
|
||||
<item name="stone" amount="4"/>
|
||||
</set>
|
||||
<set name="autoseed_unit">
|
||||
<set name="seed_unit">
|
||||
<item name="log" amount="50"/>
|
||||
<item name="stone" amount="50"/>
|
||||
<item name="iron" amount="50"/>
|
||||
|
@ -38,7 +38,7 @@
|
|||
<skill name="perception" level="30"/>
|
||||
<skill name="melee" level="1"/>
|
||||
</set>
|
||||
<set name="autoseed_faction">
|
||||
<set name="seed_faction">
|
||||
<item name="adamantium" amount="1"/>
|
||||
</set>
|
||||
</equipment>
|
||||
|
|
|
@ -88,7 +88,7 @@
|
|||
"rules.economy.herbrot": 0,
|
||||
"rules.region_owner_pay_building": "market harbour lighthouse",
|
||||
"rules.dwarf_castles": true,
|
||||
"rules.limit.faction": 500,
|
||||
"rules.limit.faction": 250,
|
||||
"rules.grow.formula": 1,
|
||||
"rules.tactics.formula": 1,
|
||||
"rules.help.mask": "fight guard money give",
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#!/bin/bash
|
||||
|
||||
GAME=$1
|
||||
TURN=$2
|
||||
|
||||
|
@ -7,6 +9,7 @@ if [ ! -d $ERESSEA/game-$GAME ] ; then
|
|||
fi
|
||||
|
||||
cd $ERESSEA/game-$GAME
|
||||
|
||||
if [ -d orders.dir.$TURN ]; then
|
||||
echo "orders.dir.$TURN already exists"
|
||||
else
|
||||
|
@ -14,3 +17,12 @@ else
|
|||
mkdir -p orders.dir
|
||||
fi
|
||||
ls -1rt orders.dir.$TURN/turn-* | xargs cat > orders.$TURN
|
||||
|
||||
lockfile -r3 -l120 orders.queue.lock
|
||||
if [ -e orders.queue ] ; then
|
||||
mv orders.queue orders.dir.$TURN/orders.queue
|
||||
fi
|
||||
rm -f orders.queue.lock
|
||||
fi
|
||||
|
||||
|
||||
|
|
|
@ -4990,12 +4990,12 @@
|
|||
<string name="sacrifice_strength">
|
||||
<text locale="de">Mit Hilfe dieses Zaubers kann der Magier einen Teil
|
||||
seiner magischen Kraft permanent auf einen anderen Magier übertragen.
|
||||
Auf einen Tybied-Magier kann er die Hälfte der eingesetzten Kraft
|
||||
übertragen, auf einen Magier eines anderen Gebietes ein Drittel.</text>
|
||||
Auf einen Magier des selben Magiegebietes kann er die Hälfte der
|
||||
eingesetzten Kraft übertragen, auf andere Magier ein Drittel.</text>
|
||||
<text locale="en">This spell allows the magician to transfer part of
|
||||
his magical powers to another magician. Tybied magicians will receive
|
||||
half the power invested, magicians of another school will receive one
|
||||
third.</text>
|
||||
his magical powers to another magician. Magicians of the seam school
|
||||
will receive half the power invested, magicians of other schoolsreceive
|
||||
receive one third.</text>
|
||||
</string>
|
||||
<string name="eternal_walls">
|
||||
<text locale="de">Mit dieser Formel bindet der Magier auf ewig die
|
||||
|
|
|
@ -7154,7 +7154,7 @@
|
|||
<text locale="de">"Das Wurmloch in $region($region) schließt sich."</text>
|
||||
<text locale="en">"The wormhole in $region($region) disappears."</text>
|
||||
</message>
|
||||
<message name="battle::useflamingsword" section="battle">
|
||||
<message name="useflamingsword" section="battle">
|
||||
<type>
|
||||
<arg name="unit" type="unit"/>
|
||||
<arg name="amount" type="int"/>
|
||||
|
@ -7162,7 +7162,7 @@
|
|||
<text locale="de">"$int($amount) Krieger von $unit($unit) benutzen ihre Flammenschwerter."</text>
|
||||
<text locale="en">"$int($amount) fighters of $unit($unit) are using their flaming sword."</text>
|
||||
</message>
|
||||
<message name="battle::usecatapult" section="battle">
|
||||
<message name="usecatapult" section="battle">
|
||||
<type>
|
||||
<arg name="unit" type="unit"/>
|
||||
<arg name="amount" type="int"/>
|
||||
|
@ -7170,35 +7170,35 @@
|
|||
<text locale="de">"$int($amount) Krieger von $unit($unit) feuern ihre Katapulte ab."</text>
|
||||
<text locale="en">"$int($amount) fighters of $unit($unit) launch their catapults."</text>
|
||||
</message>
|
||||
<message name="battle::starters" section="battle">
|
||||
<message name="start_battle" section="battle">
|
||||
<type>
|
||||
<arg name="factions" type="string"/>
|
||||
</type>
|
||||
<text locale="de">"Der Kampf wurde ausgelöst von ${factions}."</text>
|
||||
<text locale="en">"The battle was initiated by ${factions}."</text>
|
||||
</message>
|
||||
<message name="battle::potionsave" section="battle">
|
||||
<message name="potionsave" section="battle">
|
||||
<type>
|
||||
<arg name="unit" type="unit"/>
|
||||
</type>
|
||||
<text locale="de">"Eine Person von $unit($unit) konnte durch einen Heiltrank überleben."</text>
|
||||
<text locale="en">"A fighter of $unit($unit) was saved by a healing potion."</text>
|
||||
</message>
|
||||
<message name="battle::tactics_lost" section="battle">
|
||||
<message name="tactics_lost" section="battle">
|
||||
<type>
|
||||
<arg name="unit" type="unit"/>
|
||||
</type>
|
||||
<text locale="de">"$unit($unit) konnte dem Gegner eine Falle stellen."</text>
|
||||
<text locale="en">"$unit($unit) lured the enemy into an ambush."</text>
|
||||
</message>
|
||||
<message name="battle::tactics_won" section="battle">
|
||||
<message name="tactics_won" section="battle">
|
||||
<type>
|
||||
<arg name="unit" type="unit"/>
|
||||
</type>
|
||||
<text locale="de">"$unit($unit) überrascht den Gegner."</text>
|
||||
<text locale="en">"$unit($unit) surprises the enemies."</text>
|
||||
</message>
|
||||
<message name="battle::spell_failed" section="battle">
|
||||
<message name="spell_failed" section="battle">
|
||||
<type>
|
||||
<arg name="unit" type="unit"/>
|
||||
<arg name="spell" type="spell"/>
|
||||
|
@ -7206,20 +7206,20 @@
|
|||
<text locale="de">"$unit($unit) versucht $spell($spell) zu zaubern, doch der Zauber schlägt fehl!"</text>
|
||||
<text locale="en">"$unit($unit) tries to cast $spell($spell), but the spell fails!"</text>
|
||||
</message>
|
||||
<message name="battle::aborted" section="battle">
|
||||
<message name="aborted_battle" section="battle">
|
||||
<type>
|
||||
</type>
|
||||
<text locale="de">"Der Kampf wurde abgebrochen, da alle Verteidiger flohen."</text>
|
||||
<text locale="en">"The battle was aborted because all enemies escaped."</text>
|
||||
</message>
|
||||
<message name="battle::row_header" section="battle">
|
||||
<message name="battle_row" section="battle">
|
||||
<type>
|
||||
<arg name="row" type="int"/>
|
||||
</type>
|
||||
<text locale="de">"... in der $int($row). Kampflinie:"</text>
|
||||
<text locale="en">"... in combat rank $int($row):"</text>
|
||||
</message>
|
||||
<message name="battle::out_of_range" section="battle">
|
||||
<message name="spell_out_of_range" section="battle">
|
||||
<type>
|
||||
<arg name="mage" type="unit"/>
|
||||
<arg name="spell" type="spell"/>
|
||||
|
@ -7228,14 +7228,14 @@
|
|||
<text locale="en">"$unit($mage) casts $spell($spell), but nobody was in range."</text>
|
||||
</message>
|
||||
|
||||
<message name="battle::after" section="battle">
|
||||
<message name="after_battle" section="battle">
|
||||
<type>
|
||||
</type>
|
||||
<text locale="de">"Einheiten nach dem Kampf:"</text>
|
||||
<text locale="en">"Units after the battle:"</text>
|
||||
</message>
|
||||
|
||||
<message name="battle::section" section="battle">
|
||||
<message name="section_battle" section="battle">
|
||||
<type>
|
||||
</type>
|
||||
<text locale="de">""</text>
|
||||
|
@ -7301,21 +7301,21 @@
|
|||
<text locale="en">"$unit($mage) causes the walls of $building($building) to glow in an eerie magic light."</text>
|
||||
</message>
|
||||
|
||||
<message name="battle::lineup" section="battle">
|
||||
<message name="lineup_battle" section="battle">
|
||||
<type>
|
||||
<arg name="turn" type="int"/>
|
||||
</type>
|
||||
<text locale="de">"Einheiten vor der $int($turn). Runde:"</text>
|
||||
<text locale="en">"Units before turn $int($turn):"</text>
|
||||
</message>
|
||||
<message name="battle::header" section="battle">
|
||||
<message name="header_battle" section="battle">
|
||||
<type>
|
||||
<arg name="region" type="region"/>
|
||||
</type>
|
||||
<text locale="de">"In $region($region) findet ein Kampf statt."</text>
|
||||
<text locale="en">"There is a battle in $region($region)."</text>
|
||||
</message>
|
||||
<message name="battle::combatspell" section="battle">
|
||||
<message name="cast_combatspell" section="battle">
|
||||
<type>
|
||||
<arg name="mage" type="unit"/>
|
||||
<arg name="spell" type="spell"/>
|
||||
|
@ -7516,7 +7516,7 @@
|
|||
<text locale="en">"$unit($mage) casts $spell($spell). $int($amount) fighters are temporarily losing some of their memories."</text>
|
||||
</message>
|
||||
|
||||
<message name="battle::killed" section="battle">
|
||||
<message name="killed_battle" section="battle">
|
||||
<type>
|
||||
<arg name="unit" type="unit"/>
|
||||
<arg name="dead" type="int"/>
|
||||
|
@ -7524,7 +7524,7 @@
|
|||
<text locale="de">"$unit($unit) tötete $int($dead) Krieger."</text>
|
||||
<text locale="en">"$unit($unit) killed $int($dead) opponents."</text>
|
||||
</message>
|
||||
<message name="battle::army_report" section="battle">
|
||||
<message name="army_report" section="battle">
|
||||
<type>
|
||||
<arg name="index" type="int"/>
|
||||
<arg name="abbrev" type="string"/>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0"?>
|
||||
<equipment>
|
||||
|
||||
<set name="seaserpent_spoils">
|
||||
<set name="spo_seaserpent">
|
||||
<item name="dragonblood" amount="2"/>
|
||||
<item name="seaserpenthead" amount="1"/>
|
||||
</set>
|
||||
|
|
|
@ -2,27 +2,27 @@
|
|||
<equipment>
|
||||
|
||||
<!-- equipment given to familiars -->
|
||||
<set name="lynx_familiar">
|
||||
<set name="fam_lynx">
|
||||
<skill name="magic" level="1"/>
|
||||
</set>
|
||||
|
||||
<set name="tunnelworm_familiar">
|
||||
<set name="fam_tunnelworm">
|
||||
<skill name="magic" level="1"/>
|
||||
<skill name="mining" level="1"/>
|
||||
<skill name="forestry" level="1"/>
|
||||
<skill name="stamina" level="1"/>
|
||||
</set>
|
||||
|
||||
<set name="eagle_familiar">
|
||||
<set name="fam_eagle">
|
||||
<skill name="magic" level="1"/>
|
||||
</set>
|
||||
|
||||
<set name="rat_familiar">
|
||||
<set name="fam_rat">
|
||||
<skill name="magic" level="1"/>
|
||||
<skill name="stamina" level="6"/>
|
||||
</set>
|
||||
|
||||
<set name="songdragon_familiar">
|
||||
<set name="fam_songdragon">
|
||||
<skill name="magic" level="1"/>
|
||||
<!-- spells -->
|
||||
<spell name="flee" level="2"/>
|
||||
|
@ -30,7 +30,7 @@
|
|||
<spell name="frighten" level="8"/>
|
||||
</set>
|
||||
|
||||
<set name="nymph_familiar">
|
||||
<set name="fam_nymph">
|
||||
<skill name="magic" level="1"/>
|
||||
<skill name="bow" level="1"/>
|
||||
<skill name="training" level="1"/>
|
||||
|
@ -42,7 +42,7 @@
|
|||
<spell name="appeasement" level="1"/>
|
||||
</set>
|
||||
|
||||
<set name="unicorn_familiar">
|
||||
<set name="fam_unicorn">
|
||||
<skill name="magic" level="1"/>
|
||||
<!-- spells -->
|
||||
<spell name="resist_magic" level="3"/>
|
||||
|
@ -53,11 +53,11 @@
|
|||
<spell name="appeasement" level="1"/>
|
||||
</set>
|
||||
|
||||
<set name="direwolf_familiar">
|
||||
<set name="fam_direwolf">
|
||||
<skill name="magic" level="1"/>
|
||||
</set>
|
||||
|
||||
<set name="ghost_familiar">
|
||||
<set name="fam_ghost">
|
||||
<skill name="magic" level="1"/>
|
||||
<!-- spells -->
|
||||
<spell name="steal_aura" level="6"/>
|
||||
|
@ -65,7 +65,7 @@
|
|||
<spell name="summonundead" level="6"/>
|
||||
</set>
|
||||
|
||||
<set name="imp_familiar">
|
||||
<set name="fam_imp">
|
||||
<skill name="magic" level="1"/>
|
||||
<!-- spells -->
|
||||
<spell name="steal_aura" level="6"/>
|
||||
|
@ -73,14 +73,14 @@
|
|||
<spell name="seduction" level="6"/>
|
||||
</set>
|
||||
|
||||
<set name="dreamcat_familiar">
|
||||
<set name="fam_dreamcat">
|
||||
<skill name="magic" level="1"/>
|
||||
<!-- spells -->
|
||||
<spell name="shapeshift" level="3"/>
|
||||
<spell name="transferauratraum" level="3"/>
|
||||
</set>
|
||||
|
||||
<set name="fairy_familiar">
|
||||
<set name="fam_fairy">
|
||||
<skill name="magic" level="1"/>
|
||||
<!-- spells -->
|
||||
<spell name="appeasement" level="1"/>
|
||||
|
@ -88,15 +88,15 @@
|
|||
<spell name="seduction" level="6"/>
|
||||
</set>
|
||||
|
||||
<set name="owl_familiar">
|
||||
<set name="fam_owl">
|
||||
<skill name="magic" level="1"/>
|
||||
</set>
|
||||
|
||||
<set name="hellcat_familiar">
|
||||
<set name="fam_hellcat">
|
||||
<skill name="magic" level="1"/>
|
||||
</set>
|
||||
|
||||
<set name="tiger_familiar">
|
||||
<set name="fam_tiger">
|
||||
<skill name="magic" level="1"/>
|
||||
</set>
|
||||
|
||||
|
|
|
@ -830,7 +830,7 @@
|
|||
<attack type="1" damage="1d7"/>
|
||||
</race>
|
||||
|
||||
<race name="shadowknight" maxaura="0.000000" regaura="0.000000" weight="1000" capacity="540" speed="1.0" hp="1" damage="1d1" unarmedattack="0" unarmeddefense="0" attackmodifier="1" defensemodifier="1" scarepeasants="yes" walk="yes" canlearn="no" teach="no" noblock="yes">
|
||||
<race name="shadowknight" maxaura="0.000000" regaura="0.000000" weight="0" capacity="540" speed="1.0" hp="1" damage="1d1" unarmedattack="0" unarmeddefense="0" attackmodifier="1" defensemodifier="1" scarepeasants="yes" walk="yes" canlearn="no" teach="no" noblock="yes">
|
||||
<ai splitsize="20000" moverandom="yes"/>
|
||||
<attack type="1" damage="1d1"/>
|
||||
</race>
|
||||
|
|
|
@ -2,18 +2,18 @@
|
|||
<equipment>
|
||||
|
||||
<!-- one equipment-set per player-race for the first unit in a faction -->
|
||||
<set name="autoseed_dwarf">
|
||||
<set name="seed_dwarf">
|
||||
<item name="axe" amount="1"/>
|
||||
<item name="chainmail" amount="1"/>
|
||||
<skill name="melee" level="1"/>
|
||||
</set>
|
||||
|
||||
<set name="autoseed_elf">
|
||||
<set name="seed_elf">
|
||||
<item name="fairyboot" amount="1"/>
|
||||
<callback name="equip_newunits"/>
|
||||
</set>
|
||||
|
||||
<set name="autoseed_orc">
|
||||
<set name="seed_orc">
|
||||
<skill name="polearm" level="4"/>
|
||||
<skill name="melee" level="4"/>
|
||||
<skill name="crossbow" level="4"/>
|
||||
|
@ -21,30 +21,30 @@
|
|||
<skill name="bow" level="4"/>
|
||||
</set>
|
||||
|
||||
<set name="autoseed_goblin">
|
||||
<set name="seed_goblin">
|
||||
<item name="roi" amount="1"/>
|
||||
<callback name="equip_newunits"/>
|
||||
</set>
|
||||
|
||||
<set name="autoseed_human">
|
||||
<set name="seed_human">
|
||||
<callback name="equip_newunits"/>
|
||||
</set>
|
||||
|
||||
<set name="autoseed_troll">
|
||||
<set name="seed_troll">
|
||||
<skill name="building" level="1"/>
|
||||
<skill name="perception" level="3"/>
|
||||
<item name="stone" amount="50"/>
|
||||
</set>
|
||||
|
||||
<set name="autoseed_demon">
|
||||
<set name="seed_demon">
|
||||
<skill name="stamina" level="15"/>
|
||||
</set>
|
||||
|
||||
<set name="autoseed_insect">
|
||||
<set name="seed_insect">
|
||||
<item name="nestwarmth" amount="9"/>
|
||||
</set>
|
||||
|
||||
<set name="autoseed_halfling">
|
||||
<set name="seed_halfling">
|
||||
<skill name="trade" level="1"/>
|
||||
<skill name="riding" level="2"/>
|
||||
<item name="horse" amount="2"/>
|
||||
|
@ -58,18 +58,18 @@
|
|||
<item name="incense" amount="5"/>
|
||||
</set>
|
||||
|
||||
<set name="autoseed_cat">
|
||||
<set name="seed_cat">
|
||||
<item name="roi" amount="1"/>
|
||||
<callback name="equip_newunits"/>
|
||||
</set>
|
||||
|
||||
<set name="autoseed_aquarian">
|
||||
<set name="seed_aquarian">
|
||||
<skill name="sailing" level="1"/>
|
||||
<callback name="equip_newunits"/>
|
||||
</set>
|
||||
|
||||
<!-- equipment-sets for random encounters -->
|
||||
<set name="random_desert">
|
||||
<set name="rand_desert">
|
||||
<skill name="melee" level="d2"/>
|
||||
<skill name="trade" level="d3"/>
|
||||
<skill name="riding" level="d2+1"/>
|
||||
|
@ -79,53 +79,53 @@
|
|||
<item name="money" amount="d30+19"/>
|
||||
</set>
|
||||
|
||||
<set name="random_swamp">
|
||||
<set name="rand_swamp">
|
||||
<skill name="stealth" level="d3+1"/>
|
||||
<skill name="polearm" level="d3+1"/>
|
||||
<item name="spear" amount="1"/>
|
||||
<item name="money" amount="d20+9"/>
|
||||
</set>
|
||||
|
||||
<set name="random_glacier">
|
||||
<set name="rand_glacier">
|
||||
<skill name="armorer" level="d2+1"/>
|
||||
<skill name="melee" level="d2+1"/>
|
||||
<item name="sword" amount="1"/>
|
||||
<item name="money" amount="d20+19"/>
|
||||
</set>
|
||||
|
||||
<set name="random_mountain">
|
||||
<set name="rand_mountain">
|
||||
<skill name="armorer" level="d2+1"/>
|
||||
<skill name="melee" level="d2+1"/>
|
||||
<skill name="trade" level="d3"/>
|
||||
<item name="sword" amount="1"/>
|
||||
<item name="money" amount="d40+59"/>
|
||||
<subset chance="0.6">
|
||||
<set name="item_plate"/>
|
||||
<set name="i_plate"/>
|
||||
</subset>
|
||||
</set>
|
||||
|
||||
<set name="random_highland">
|
||||
<set name="rand_highland">
|
||||
<skill name="melee" level="d2"/>
|
||||
<item name="sword" amount="1"/>
|
||||
<item name="money" amount="d10+19"/>
|
||||
</set>
|
||||
|
||||
<set name="random_forest">
|
||||
<set name="rand_forest">
|
||||
<skill name="stealth" level="d2"/>
|
||||
<skill name="perception" level="d2+1"/>
|
||||
<skill name="bow" level="d3+1"/>
|
||||
<item name="bow" amount="1"/>
|
||||
<item name="money" amount="d20+9"/>
|
||||
<subset chance="0.2">
|
||||
<set name="random_herbalist"/>
|
||||
<set name="rand_herbalist"/>
|
||||
</subset>
|
||||
</set>
|
||||
|
||||
<set name="random_herbalist">
|
||||
<set name="rand_herbalist">
|
||||
<skill name="herbalism" level="d2"/>
|
||||
</set>
|
||||
|
||||
<set name="random_villagers">
|
||||
<set name="rand_villagers">
|
||||
<item name="money" amount="d80+19"/>
|
||||
<skill name="cartmaking" level="d2-1"/>
|
||||
<skill name="mining" level="d2-1"/>
|
||||
|
@ -136,57 +136,57 @@
|
|||
<item name="money" amount="d30+10"/>
|
||||
</set>
|
||||
|
||||
<set name="random_plain">
|
||||
<set name="rand_plain">
|
||||
<item name="money" amount="d80+19"/>
|
||||
<subset>
|
||||
<set name="random_sword" chance="0.25"/>
|
||||
<set name="random_spear" chance="0.25"/>
|
||||
<set name="random_crossbow" chance="0.25"/>
|
||||
<set name="random_bow" chance="0.25"/>
|
||||
<set name="rand_sword" chance="0.25"/>
|
||||
<set name="rand_spear" chance="0.25"/>
|
||||
<set name="rand_crossbow" chance="0.25"/>
|
||||
<set name="rand_bow" chance="0.25"/>
|
||||
</subset>
|
||||
<subset chance="0.4">
|
||||
<set name="item_chain"/>
|
||||
<set name="i_chain"/>
|
||||
</subset>
|
||||
<subset chance="0.3">
|
||||
<set name="random_rider"/>
|
||||
<set name="rand_rider"/>
|
||||
</subset>
|
||||
</set>
|
||||
|
||||
<set name="random_spear">
|
||||
<set name="rand_spear">
|
||||
<skill name="polearm" level="d3"/>
|
||||
<item name="spear" amount="1"/>
|
||||
</set>
|
||||
|
||||
<set name="random_sword">
|
||||
<set name="rand_sword">
|
||||
<skill name="melee" level="d3"/>
|
||||
<item name="sword" amount="1"/>
|
||||
</set>
|
||||
|
||||
<set name="random_crossbow">
|
||||
<set name="rand_crossbow">
|
||||
<skill name="crossbow" level="d3"/>
|
||||
<item name="crossbow" amount="1"/>
|
||||
</set>
|
||||
|
||||
<set name="random_bow">
|
||||
<set name="rand_bow">
|
||||
<skill name="bow" level="d3"/>
|
||||
<item name="bow" amount="1"/>
|
||||
</set>
|
||||
|
||||
<set name="random_rider">
|
||||
<set name="rand_rider">
|
||||
<item name="horse" amount="1"/>
|
||||
<skill name="riding" level="d3"/>
|
||||
</set>
|
||||
|
||||
<set name="recruited_dracoid">
|
||||
<set name="new_dracoid">
|
||||
<!-- dracoiden, von drachen rekrutiert -->
|
||||
<skill name="polearm" level="d4+2"/>
|
||||
<skill name="melee" level="d4+2"/>
|
||||
<skill name="bow" level="d3+1"/>
|
||||
<subset>
|
||||
<!-- dracoiden haben immer eine von drei waffen -->
|
||||
<set name="item_sword" chance="0.33"/>
|
||||
<set name="item_spear" chance="0.33"/>
|
||||
<set name="item_bow" chance="0.34"/>
|
||||
<set name="i_sword" chance="0.33"/>
|
||||
<set name="i_spear" chance="0.33"/>
|
||||
<set name="i_bow" chance="0.34"/>
|
||||
</subset>
|
||||
</set>
|
||||
|
||||
|
@ -195,56 +195,52 @@
|
|||
<item name="rustysword" amount="1"/>
|
||||
<item name="rustychainmail" amount="d2-1"/>
|
||||
<subset chance="0.3">
|
||||
<set name="item_rustyshield"/>
|
||||
<set name="i_rustyshield"/>
|
||||
</subset>
|
||||
</set>
|
||||
|
||||
|
||||
<!-- single-item sets (that can be given a percentage-chance in a subset) -->
|
||||
<set name="item_plate">
|
||||
<set name="i_plate">
|
||||
<item name="plate" amount="1"/>
|
||||
</set>
|
||||
|
||||
<set name="item_spear">
|
||||
<set name="i_spear">
|
||||
<item name="spear" amount="1"/>
|
||||
</set>
|
||||
|
||||
<set name="item_bow">
|
||||
<set name="i_bow">
|
||||
<item name="bow" amount="1"/>
|
||||
</set>
|
||||
|
||||
<set name="item_sword">
|
||||
<set name="i_sword">
|
||||
<item name="sword" amount="1"/>
|
||||
</set>
|
||||
|
||||
<set name="item_chain">
|
||||
<set name="i_chain">
|
||||
<item name="chainmail" amount="1"/>
|
||||
</set>
|
||||
|
||||
<set name="item_log">
|
||||
<item name="log" amount="1"/>
|
||||
<set name="i_rustyshield">
|
||||
<item name="rustyshield" amount="1"/>
|
||||
</set>
|
||||
|
||||
<set name="item_rustychain">
|
||||
<item name="rustychainmail" amount="1"/>
|
||||
</set>
|
||||
|
||||
<set name="dragon_spoils">
|
||||
<set name="spo_dragon">
|
||||
<item name="dragonblood" amount="4"/>
|
||||
<item name="dragonhead" amount="1"/>
|
||||
</set>
|
||||
|
||||
<set name="youngdragon_spoils">
|
||||
<set name="spo_youngdragon">
|
||||
<item name="dragonblood" amount="1"/>
|
||||
</set>
|
||||
|
||||
<set name="wyrm_spoils">
|
||||
<set name="spo_wyrm">
|
||||
<item name="dragonblood" amount="10"/>
|
||||
<item name="dragonhead" amount="1"/>
|
||||
</set>
|
||||
|
||||
<!-- sets that are used by the monster-spawning code -->
|
||||
<set name="monster_dragon">
|
||||
<set name="seed_dragon">
|
||||
<skill name="magic" level="4"/>
|
||||
<skill name="stealth" level="1"/>
|
||||
<skill name="stamina" level="1"/>
|
||||
|
@ -252,24 +248,24 @@
|
|||
<item name="money" amount="d500+99"/>
|
||||
</set>
|
||||
|
||||
<set name="monster_braineater">
|
||||
<set name="seed_braineater">
|
||||
<skill name="stealth" level="1"/>
|
||||
<skill name="perception" level="1"/>
|
||||
</set>
|
||||
|
||||
<set name="monster_seaserpent">
|
||||
<set name="seed_seaserpent">
|
||||
<skill name="magic" level="4"/>
|
||||
<skill name="stealth" level="2"/>
|
||||
<skill name="stamina" level="1"/>
|
||||
<skill name="perception" level="3"/>
|
||||
</set>
|
||||
|
||||
<set name="new_orc_unit">
|
||||
<set name="new_orc">
|
||||
<skill name="polearm" level="1"/>
|
||||
<skill name="melee" level="1"/>
|
||||
</set>
|
||||
|
||||
<set name="seaserpent_spoils">
|
||||
<set name="spo_seaserpent">
|
||||
<item name="dragonblood" amount="6"/>
|
||||
<item name="seaserpenthead" amount="1"/>
|
||||
</set>
|
||||
|
|
|
@ -2,26 +2,26 @@
|
|||
<equipment>
|
||||
|
||||
<!-- equipment given to familiars -->
|
||||
<set name="lynx_familiar">
|
||||
<set name="fam_lynx">
|
||||
<skill name="espionage" level="1"/>
|
||||
<skill name="magic" level="1"/>
|
||||
<skill name="stealth" level="1"/>
|
||||
<skill name="perception" level="1"/>
|
||||
</set>
|
||||
|
||||
<set name="tunnelworm_familiar">
|
||||
<set name="fam_tunnelworm">
|
||||
<skill name="magic" level="1"/>
|
||||
<skill name="mining" level="1"/>
|
||||
<skill name="forestry" level="1"/>
|
||||
<skill name="stamina" level="1"/>
|
||||
</set>
|
||||
|
||||
<set name="eagle_familiar">
|
||||
<set name="fam_eagle">
|
||||
<skill name="magic" level="1"/>
|
||||
<skill name="perception" level="1"/>
|
||||
</set>
|
||||
|
||||
<set name="rat_familiar">
|
||||
<set name="fam_rat">
|
||||
<skill name="magic" level="1"/>
|
||||
<skill name="espionage" level="1"/>
|
||||
<skill name="stealth" level="1"/>
|
||||
|
@ -29,7 +29,7 @@
|
|||
<skill name="stamina" level="6"/>
|
||||
</set>
|
||||
|
||||
<set name="songdragon_familiar">
|
||||
<set name="fam_songdragon">
|
||||
<skill name="magic" level="1"/>
|
||||
<!-- spells -->
|
||||
<spell name="flee" level="2"/>
|
||||
|
@ -37,7 +37,7 @@
|
|||
<spell name="frighten" level="8"/>
|
||||
</set>
|
||||
|
||||
<set name="nymph_familiar">
|
||||
<set name="fam_nymph">
|
||||
<skill name="magic" level="1"/>
|
||||
<skill name="bow" level="1"/>
|
||||
<skill name="herbalism" level="1"/>
|
||||
|
@ -54,7 +54,7 @@
|
|||
<spell name="appeasement" level="1"/>
|
||||
</set>
|
||||
|
||||
<set name="unicorn_familiar">
|
||||
<set name="fam_unicorn">
|
||||
<skill name="magic" level="1"/>
|
||||
<skill name="stealth" level="1"/>
|
||||
<skill name="perception" level="1"/>
|
||||
|
@ -67,12 +67,12 @@
|
|||
<spell name="appeasement" level="1"/>
|
||||
</set>
|
||||
|
||||
<set name="direwolf_familiar">
|
||||
<set name="fam_direwolf">
|
||||
<skill name="magic" level="1"/>
|
||||
<skill name="perception" level="1"/>
|
||||
</set>
|
||||
|
||||
<set name="ghost_familiar">
|
||||
<set name="fam_ghost">
|
||||
<skill name="magic" level="1"/>
|
||||
<!-- spells -->
|
||||
<spell name="steal_aura" level="6"/>
|
||||
|
@ -80,7 +80,7 @@
|
|||
<spell name="summonundead" level="6"/>
|
||||
</set>
|
||||
|
||||
<set name="imp_familiar">
|
||||
<set name="fam_imp">
|
||||
<skill name="magic" level="1"/>
|
||||
<skill name="espionage" level="1"/>
|
||||
<skill name="stealth" level="1"/>
|
||||
|
@ -92,7 +92,7 @@
|
|||
<spell name="seduction" level="6"/>
|
||||
</set>
|
||||
|
||||
<set name="dreamcat_familiar">
|
||||
<set name="fam_dreamcat">
|
||||
<skill name="magic" level="1"/>
|
||||
<skill name="espionage" level="1"/>
|
||||
<skill name="stealth" level="1"/>
|
||||
|
@ -103,7 +103,7 @@
|
|||
<spell name="transferauratraum" level="3"/>
|
||||
</set>
|
||||
|
||||
<set name="fairy_familiar">
|
||||
<set name="fam_fairy">
|
||||
<skill name="magic" level="1"/>
|
||||
<!-- spells -->
|
||||
<spell name="appeasement" level="1"/>
|
||||
|
@ -111,19 +111,19 @@
|
|||
<spell name="seduction" level="6"/>
|
||||
</set>
|
||||
|
||||
<set name="owl_familiar">
|
||||
<set name="fam_owl">
|
||||
<skill name="magic" level="1"/>
|
||||
<skill name="espionage" level="1"/>
|
||||
<skill name="stealth" level="1"/>
|
||||
<skill name="perception" level="1"/>
|
||||
</set>
|
||||
|
||||
<set name="hellcat_familiar">
|
||||
<set name="fam_hellcat">
|
||||
<skill name="magic" level="1"/>
|
||||
<skill name="perception" level="1"/>
|
||||
</set>
|
||||
|
||||
<set name="tiger_familiar">
|
||||
<set name="fam_tiger">
|
||||
<skill name="magic" level="1"/>
|
||||
<skill name="perception" level="1"/>
|
||||
</set>
|
||||
|
|
|
@ -1071,7 +1071,7 @@
|
|||
<skill name="unarmed" modifier="1"/>
|
||||
<attack type="1" damage="1d7"/>
|
||||
</race>
|
||||
<race name="shadowknight" maxaura="0.000000" regaura="0.000000" weight="1000" capacity="540" speed="1.000000" hp="1" damage="1d1" unarmedattack="0" unarmeddefense="0" attackmodifier="1" defensemodifier="1" scarepeasants="yes" walk="yes" canlearn="no" teach="no" noblock="yes">
|
||||
<race name="shadowknight" maxaura="0.000000" regaura="0.000000" weight="0" capacity="540" speed="1.000000" hp="1" damage="1d1" unarmedattack="0" unarmeddefense="0" attackmodifier="1" defensemodifier="1" scarepeasants="yes" walk="yes" canlearn="no" teach="no" noblock="yes">
|
||||
<ai splitsize="20000" moverandom="yes"/>
|
||||
<attack type="1" damage="1d1"/>
|
||||
</race>
|
||||
|
|
21
s/runtests
21
s/runtests
|
@ -4,18 +4,29 @@ set -e
|
|||
ROOT=$(git rev-parse --show-toplevel)
|
||||
[ -z $BUILD ] && BUILD=Debug ; export BUILD
|
||||
|
||||
UNIT_TESTS=$BUILD/eressea/test_eressea
|
||||
RUN_TESTS=$BUILD/eressea/eressea
|
||||
if [ "$1" = "-V" ]; then
|
||||
VALGRIND=$(which valgrind)
|
||||
if [ -n "$VALGRIND" ]; then
|
||||
SUPP=share/ubuntu-12_04.supp
|
||||
UNIT_TESTS="$VALGRIND --quiet --suppressions=$SUPP --error-exitcode=1 --leak-check=no $UNIT_TESTS"
|
||||
RUN_TESTS="$VALGRIND --quiet --suppressions=$SUPP --error-exitcode=1 --leak-check=no $RUN_TESTS"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -e $ROOT/$BUILD ]; then
|
||||
echo "cannot find build directory $BUILD in $ROOT. did you run cmake-init?"
|
||||
exit
|
||||
fi
|
||||
|
||||
$ROOT/$BUILD/eressea/test_eressea
|
||||
$UNIT_TESTS
|
||||
cd $ROOT
|
||||
[ -e eressea.ini ] || ln -sf conf/eressea.ini
|
||||
$ROOT/$BUILD/eressea/eressea -v1 scripts/run-tests.lua
|
||||
$ROOT/$BUILD/eressea/eressea -v1 scripts/run-tests-e2.lua
|
||||
$ROOT/$BUILD/eressea/eressea -v1 scripts/run-tests-e3.lua
|
||||
$ROOT/$BUILD/eressea/eressea --version
|
||||
$RUN_TESTS -v1 scripts/run-tests.lua
|
||||
$RUN_TESTS -v1 scripts/run-tests-e2.lua
|
||||
$RUN_TESTS -v1 scripts/run-tests-e3.lua
|
||||
$RUN_TESTS --version
|
||||
rm -rf data reports orders.txt score score.alliances datum turn
|
||||
|
||||
cd $OLDWPD
|
||||
|
|
|
@ -22,6 +22,6 @@ s/cmake-init
|
|||
s/build
|
||||
cd $ROOT
|
||||
inifile
|
||||
s/runtests
|
||||
s/runtests -V
|
||||
|
||||
integration_tests
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
if not config.autoseed then return nil end
|
||||
if not config.autoseed or config.autoseed==0 then return nil end
|
||||
local autoseed = {}
|
||||
|
||||
-- minimum required resources in the 7-hex neighborhood:
|
||||
|
@ -65,9 +65,9 @@ local function seed(r, email, race, lang)
|
|||
assert(f)
|
||||
local u = unit.create(f, r)
|
||||
assert(u)
|
||||
equip_unit(u, "autoseed_faction")
|
||||
equip_unit(u, "autoseed_unit")
|
||||
equip_unit(u, "autoseed_" .. race, 7)
|
||||
equip_unit(u, "seed_faction")
|
||||
equip_unit(u, "seed_unit")
|
||||
equip_unit(u, "seed_" .. race, 7)
|
||||
unit.create(f, r, 5):set_skill("mining", 30)
|
||||
unit.create(f, r, 5):set_skill("quarrying", 30)
|
||||
f:set_origin(r)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
-- Muschelplateau
|
||||
|
||||
if not config.embassy then return nil end
|
||||
if not config.embassy or config.embassy==0 then return nil end
|
||||
|
||||
local embassy = {}
|
||||
local home = nil
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
-- DEPRECATED
|
||||
if not config.eternath then return nil end
|
||||
if not config.eternath or config.eternath==0 then return nil end
|
||||
-- implements parts of a quest in E2
|
||||
-- this module is deprecated, because it puts functions in the global environment for at_building_action
|
||||
|
||||
|
|
21
scripts/eressea/modules.lua
Normal file
21
scripts/eressea/modules.lua
Normal file
|
@ -0,0 +1,21 @@
|
|||
local modules = {}
|
||||
|
||||
function add_module(pkg)
|
||||
table.insert(modules, pkg)
|
||||
end
|
||||
|
||||
local pkg = {}
|
||||
|
||||
function pkg.init()
|
||||
for k, v in ipairs(modules) do
|
||||
if v.init then v.init() end
|
||||
end
|
||||
end
|
||||
|
||||
function pkg.update()
|
||||
for k, v in ipairs(modules) do
|
||||
if v.update then v.update() end
|
||||
end
|
||||
end
|
||||
|
||||
return pkg
|
|
@ -1,4 +1,4 @@
|
|||
if not config.ponnuki then return nil end
|
||||
if not config.ponnuki or config.ponnuki==0 then return nil end
|
||||
local ponnuki = {}
|
||||
|
||||
local directions = { "NW", "NO", "O", "SO", "SW", "W" }
|
||||
|
|
|
@ -19,44 +19,49 @@ local function create_item(mage, level, name, number)
|
|||
return level
|
||||
end
|
||||
|
||||
local function create_potion(mage, level, name, force)
|
||||
count = math.floor(force * 2 + 0.5)
|
||||
return create_item(mage, level, name, count)
|
||||
end
|
||||
|
||||
-- Wasser des Lebens
|
||||
function create_potion_p2(r, mage, level, force)
|
||||
return create_item(mage, level, "p2", level)
|
||||
return create_potion(mage, level, "p2", force)
|
||||
end
|
||||
|
||||
-- Siebenmeilentee
|
||||
function create_potion_p0(r, mage, level, force)
|
||||
return create_item(mage, level, "p0", level)
|
||||
return create_potion(mage, level, "p0", force)
|
||||
end
|
||||
|
||||
-- Wundsalbe
|
||||
function create_potion_ointment(r, mage, level, force)
|
||||
return create_item(mage, level, "ointment", level)
|
||||
return create_potion(mage, level, "ointment", force)
|
||||
end
|
||||
|
||||
-- Bauernblut
|
||||
function create_potion_peasantblood(r, mage, level, force)
|
||||
return create_item(mage, level, "peasantblood", level)
|
||||
return create_potion(mage, level, "peasantblood", force)
|
||||
end
|
||||
|
||||
-- Pferdeglueck
|
||||
function create_potion_p9(r, mage, level, force)
|
||||
return create_item(mage, level, "p9", level)
|
||||
return create_potion(mage, level, "p9", force)
|
||||
end
|
||||
|
||||
-- Schaffenstrunk
|
||||
function create_potion_p3(r, mage, level, force)
|
||||
return create_item(mage, level, "p3", level)
|
||||
return create_potion(mage, level, "p3", force)
|
||||
end
|
||||
|
||||
-- Heiltrank
|
||||
function create_potion_p14(r, mage, level, force)
|
||||
return create_item(mage, level, "p14", level)
|
||||
return create_potion(mage, level, "p14", force)
|
||||
end
|
||||
|
||||
-- Elixier der Macht
|
||||
function create_potion_p13(r, mage, level, force)
|
||||
return create_item(mage, level, "p13", level)
|
||||
return create_potion(mage, level, "p13", force)
|
||||
end
|
||||
|
||||
-- Erschaffe ein Flammenschwert
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
-- DEPRECATED
|
||||
if not config.wedding then return nil end
|
||||
if not config.wedding or config.wedding==0 then return nil end
|
||||
|
||||
-- this script contains the action functions for the two portals
|
||||
-- used on the jadee/wildente wedding island. the two _action functions
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
if not config.xmas then return nil end
|
||||
if not config.xmas or config.xmas==0 then return nil end
|
||||
|
||||
local gifts = {
|
||||
e2 = {
|
||||
|
|
|
@ -8,6 +8,7 @@ function setup()
|
|||
eressea.settings.set("rules.food.flags", "4")
|
||||
eressea.settings.set("rules.ship.storms", "0")
|
||||
eressea.settings.set("rules.encounters", "0")
|
||||
eressea.settings.set("study.produceexp", "0")
|
||||
end
|
||||
|
||||
function test_calendar()
|
||||
|
@ -57,6 +58,7 @@ function test_dwarf_bonus()
|
|||
u.building = building.create(r, "mine")
|
||||
u.building.size = 10
|
||||
u:add_item("money", 500) -- maintenance
|
||||
assert_equal(1, u:get_skill("mining"))
|
||||
process_orders()
|
||||
assert_equal(70, u:get_item("iron"))
|
||||
assert_equal(70, r:get_resource("iron"))
|
||||
|
|
|
@ -11,6 +11,26 @@ function setup()
|
|||
eressea.settings.set("rules.encounters", "0")
|
||||
end
|
||||
|
||||
function test_bug_2361_forget_magic()
|
||||
-- https://bugs.eressea.de/view.php?id=2361
|
||||
-- familiars cannot forget magic
|
||||
local r = region.create(0, 0, "plain")
|
||||
local f = faction.create("human")
|
||||
local u = unit.create(f, r, 1)
|
||||
local uf = unit.create(f, r, 1)
|
||||
u:clear_orders()
|
||||
u:add_order("VERGESSE Magie")
|
||||
u:set_skill('magic', 5)
|
||||
uf.race = 'unicorn'
|
||||
uf:clear_orders()
|
||||
uf:add_order("VERGESSE Magie")
|
||||
uf:set_skill('magic', 5)
|
||||
u.familiar = uf
|
||||
process_orders()
|
||||
assert_equal(0, u:get_skill('magic'))
|
||||
assert_equal(5, uf:get_skill('magic'))
|
||||
end
|
||||
|
||||
function test_mine_bonus()
|
||||
local r = region.create(0, 0, "mountain")
|
||||
r:set_resource("iron", 100)
|
||||
|
|
|
@ -18,8 +18,9 @@ local function file_exists(name)
|
|||
if f~=nil then io.close(f) return true else return false end
|
||||
end
|
||||
|
||||
local function assert_file(filename)
|
||||
assert_equal(true, file_exists(filename))
|
||||
local function assert_file(filename, exists)
|
||||
if exists == nil then exists = true end
|
||||
assert_equal(exists, file_exists(filename))
|
||||
os.remove(filename)
|
||||
end
|
||||
|
||||
|
@ -30,9 +31,9 @@ function test_process_turn()
|
|||
assert_equal(0, write_reports())
|
||||
assert_equal(0, eressea.write_game("test.dat"))
|
||||
assert_file("data/test.dat")
|
||||
assert_file("reports/" .. get_turn() .. "-ii.nr")
|
||||
assert_file("reports/" .. get_turn() .. "-ii.cr")
|
||||
assert_file("reports/" .. get_turn() .. "-ii.txt")
|
||||
assert_file("reports/" .. get_turn() .. "-ii.nr", false)
|
||||
assert_file("reports/" .. get_turn() .. "-ii.cr", false)
|
||||
assert_file("reports/" .. get_turn() .. "-ii.txt", false)
|
||||
assert_file("reports/" .. get_turn() .. "-777.nr")
|
||||
assert_file("reports/" .. get_turn() .. "-777.cr")
|
||||
assert_file("reports/" .. get_turn() .. "-777.txt")
|
||||
|
|
|
@ -116,6 +116,7 @@ set (ERESSEA_SRC
|
|||
magic.c
|
||||
market.c
|
||||
morale.c
|
||||
orderfile.c
|
||||
randenc.c
|
||||
renumber.c
|
||||
volcano.c
|
||||
|
@ -217,6 +218,7 @@ set(TESTS_SRC
|
|||
monsters.test.c
|
||||
move.test.c
|
||||
names.test.c
|
||||
orderfile.test.c
|
||||
piracy.test.c
|
||||
prefix.test.c
|
||||
renumber.test.c
|
||||
|
|
|
@ -22,13 +22,14 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
#include <kernel/building.h>
|
||||
#include <kernel/item.h>
|
||||
#include <kernel/pool.h>
|
||||
|
||||
#include "academy.h"
|
||||
#include "study.h"
|
||||
|
||||
void academy_teaching_bonus(struct unit *u, skill_t sk, int student_days) {
|
||||
if (student_days && sk != NOSKILL) {
|
||||
/* actually days / STUDYDAYS * EXPERIENCEDAYS / MAX_STUDENTS */
|
||||
learn_skill(u, sk, student_days / STUDYDAYS);
|
||||
void academy_teaching_bonus(struct unit *u, skill_t sk, int students) {
|
||||
if (students && sk != NOSKILL) {
|
||||
/* actually students * EXPERIENCEDAYS / MAX_STUDENTS */
|
||||
learn_skill(u, sk, students);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -96,7 +96,7 @@ static int obs_read(struct attrib *a, void *owner, struct gamedata *data)
|
|||
{
|
||||
obs_data *od = (obs_data *)a->data.v;
|
||||
|
||||
read_reference(&od->f, data, read_faction_reference, resolve_faction);
|
||||
read_faction_reference(data, &od->f, NULL);
|
||||
READ_INT(data->store, &od->skill);
|
||||
READ_INT(data->store, &od->timer);
|
||||
return AT_READ_OK;
|
||||
|
@ -114,7 +114,7 @@ static attrib *make_observer(faction *f, int perception)
|
|||
return a;
|
||||
}
|
||||
|
||||
int get_observer(region *r, faction *f) {
|
||||
int get_observer(const region *r, const faction *f) {
|
||||
if (fval(r, RF_OBSERVER)) {
|
||||
attrib *a = a_find(r->attribs, &at_observer);
|
||||
while (a && a->type == &at_observer) {
|
||||
|
|
|
@ -29,7 +29,7 @@ extern "C" {
|
|||
extern void register_attributes(void);
|
||||
|
||||
void set_observer(struct region *r, struct faction *f, int perception, int turns);
|
||||
int get_observer(struct region *r, struct faction *f);
|
||||
int get_observer(const struct region *r, const struct faction *f);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
|
||||
static int read_follow(attrib * a, void *owner, gamedata *data)
|
||||
{
|
||||
read_unit_reference(data); /* skip it */
|
||||
READ_INT(data->store, NULL); /* skip it */
|
||||
return AT_READ_FAIL;
|
||||
}
|
||||
|
||||
|
|
|
@ -45,9 +45,7 @@ write_hate(const attrib * a, const void *owner, struct storage *store)
|
|||
|
||||
static int read_hate(attrib * a, void *owner, gamedata *data)
|
||||
{
|
||||
int result = read_reference(&a->data.v, data, read_unit_reference,
|
||||
resolve_unit);
|
||||
if (result == 0 && !a->data.v) {
|
||||
if (read_unit_reference(data, (unit **)&a->data.v, NULL) <= 0) {
|
||||
return AT_READ_FAIL;
|
||||
}
|
||||
return AT_READ_OK;
|
||||
|
|
|
@ -67,8 +67,12 @@ static int keys_size(int n) {
|
|||
assert(n > 0 && n <= 4096);
|
||||
if (n <= 1) return 1;
|
||||
if (n <= 4) return 4;
|
||||
if (n <= 8) return 8;
|
||||
if (n <= 16) return 16;
|
||||
if (n <= 256) return 256;
|
||||
if (n <= 512) return 512;
|
||||
if (n <= 1024) return 1024;
|
||||
if (n <= 2048) return 2048;
|
||||
return 4096;
|
||||
}
|
||||
|
||||
|
|
|
@ -36,10 +36,9 @@ write_targetregion(const attrib * a, const void *owner, struct storage *store)
|
|||
|
||||
static int read_targetregion(attrib * a, void *owner, gamedata *data)
|
||||
{
|
||||
int result = read_reference(&a->data.v, data, read_region_reference,
|
||||
RESOLVE_REGION(data->version));
|
||||
if (result == 0 && !a->data.v)
|
||||
if (read_region_reference(data, (region **)&a->data.v, NULL) <= 0) {
|
||||
return AT_READ_FAIL;
|
||||
}
|
||||
return AT_READ_OK;
|
||||
}
|
||||
|
||||
|
|
28
src/battle.c
28
src/battle.c
|
@ -927,7 +927,7 @@ void kill_troop(troop dt)
|
|||
if (drops != NULL) {
|
||||
i_merge(&du->items, &drops);
|
||||
}
|
||||
sprintf(eqname, "%s_spoils", rc->_name);
|
||||
sprintf(eqname, "spo_%s", rc->_name);
|
||||
eq = get_equipment(eqname);
|
||||
if (eq != NULL) {
|
||||
equip_items(&du->items, eq);
|
||||
|
@ -1295,7 +1295,7 @@ terminate(troop dt, troop at, int type, const char *damage, bool missile)
|
|||
|
||||
if (oldpotiontype[P_HEAL] && !fval(&df->person[dt.index], FL_HEALING_USED)) {
|
||||
if (i_get(du->items, oldpotiontype[P_HEAL]->itype) > 0) {
|
||||
message *m = msg_message("battle::potionsave", "unit", du);
|
||||
message *m = msg_message("potionsave", "unit", du);
|
||||
message_faction(b, du->faction, m);
|
||||
msg_release(m);
|
||||
i_change(&du->items, oldpotiontype[P_HEAL]->itype, -1);
|
||||
|
@ -1630,7 +1630,7 @@ selist *fighters(battle * b, const side * vs, int minrow, int maxrow, int mask)
|
|||
|
||||
static void report_failed_spell(struct battle * b, struct unit * mage, const struct spell *sp)
|
||||
{
|
||||
message *m = msg_message("battle::spell_failed", "unit spell", mage, sp);
|
||||
message *m = msg_message("spell_failed", "unit spell", mage, sp);
|
||||
message_all(b, m);
|
||||
msg_release(m);
|
||||
}
|
||||
|
@ -2277,7 +2277,7 @@ void do_attack(fighter * af)
|
|||
* Ladezeit neu und generiert die Meldung. */
|
||||
if (af->catmsg >= 0) {
|
||||
struct message *m =
|
||||
msg_message("battle::killed", "unit dead", au, af->catmsg);
|
||||
msg_message("killed_battle", "unit dead", au, af->catmsg);
|
||||
message_all(b, m);
|
||||
msg_release(m);
|
||||
af->catmsg = -1;
|
||||
|
@ -2752,10 +2752,10 @@ static void aftermath(battle * b)
|
|||
battle_effects(b, dead_players);
|
||||
|
||||
for (s = b->sides; s != b->sides + b->nsides; ++s) {
|
||||
message *seen = msg_message("battle::army_report",
|
||||
message *seen = msg_message("army_report",
|
||||
"index abbrev dead fled survived",
|
||||
army_index(s), sideabkz(s, false), s->dead, s->flee, s->alive);
|
||||
message *unseen = msg_message("battle::army_report",
|
||||
message *unseen = msg_message("army_report",
|
||||
"index abbrev dead fled survived",
|
||||
army_index(s), "-?-", s->dead, s->flee, s->alive);
|
||||
|
||||
|
@ -2864,7 +2864,7 @@ static void print_fighters(battle * b, const side * s)
|
|||
|
||||
if (row == thisrow) {
|
||||
if (m == NULL) {
|
||||
m = msg_message("battle::row_header", "row", row);
|
||||
m = msg_message("battle_row", "row", row);
|
||||
message_all(b, m);
|
||||
}
|
||||
battle_punit(du, b);
|
||||
|
@ -2927,7 +2927,7 @@ static void print_header(battle * b)
|
|||
bufp = STRLCPY(bufp, lastf, size);
|
||||
}
|
||||
|
||||
m = msg_message("battle::starters", "factions", zText);
|
||||
m = msg_message("start_battle", "factions", zText);
|
||||
message_faction(b, f, m);
|
||||
msg_release(m);
|
||||
}
|
||||
|
@ -3049,10 +3049,10 @@ static void print_stats(battle * b)
|
|||
unit *u = tf->unit;
|
||||
message *m = NULL;
|
||||
if (!is_attacker(tf)) {
|
||||
m = msg_message("battle::tactics_lost", "unit", u);
|
||||
m = msg_message("tactics_lost", "unit", u);
|
||||
}
|
||||
else {
|
||||
m = msg_message("battle::tactics_won", "unit", u);
|
||||
m = msg_message("tactics_won", "unit", u);
|
||||
}
|
||||
message_all(b, m);
|
||||
msg_release(m);
|
||||
|
@ -3579,9 +3579,9 @@ static int battle_report(battle * b)
|
|||
message_faction(b, fac, msg_separator);
|
||||
|
||||
if (cont)
|
||||
m = msg_message("battle::lineup", "turn", b->turn);
|
||||
m = msg_message("lineup_battle", "turn", b->turn);
|
||||
else
|
||||
m = msg_message("battle::after", "");
|
||||
m = msg_message("after_battle", "");
|
||||
message_faction(b, fac, m);
|
||||
msg_release(m);
|
||||
|
||||
|
@ -4073,7 +4073,7 @@ void do_battle(region * r)
|
|||
bool fighting = false;
|
||||
ship *sh;
|
||||
if (msg_separator == NULL) {
|
||||
msg_separator = msg_message("battle::section", "");
|
||||
msg_separator = msg_message("section_battle", "");
|
||||
}
|
||||
|
||||
fighting = start_battle(r, &b);
|
||||
|
@ -4087,7 +4087,7 @@ void do_battle(region * r)
|
|||
print_header(b);
|
||||
if (!fighting) {
|
||||
/* Niemand mehr da, Kampf kann nicht stattfinden. */
|
||||
message *m = msg_message("battle::aborted", "");
|
||||
message *m = msg_message("aborted_battle", "");
|
||||
message_all(b, m);
|
||||
msg_release(m);
|
||||
free_battle(b);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <platform.h>
|
||||
|
||||
#include "json.h"
|
||||
#include "orderfile.h"
|
||||
|
||||
#include <kernel/faction.h>
|
||||
#include <kernel/item.h>
|
||||
|
|
|
@ -273,7 +273,7 @@ static int tolua_unit_set_guard(lua_State * L)
|
|||
|
||||
static const char *unit_getmagic(const unit * u)
|
||||
{
|
||||
sc_mage *mage = get_mage(u);
|
||||
sc_mage *mage = get_mage_depr(u);
|
||||
return mage ? magic_school[mage->magietyp] : NULL;
|
||||
}
|
||||
|
||||
|
@ -286,7 +286,7 @@ static int tolua_unit_get_magic(lua_State * L)
|
|||
|
||||
static void unit_setmagic(unit * u, const char *type)
|
||||
{
|
||||
sc_mage *mage = get_mage(u);
|
||||
sc_mage *mage = get_mage_depr(u);
|
||||
int mtype;
|
||||
for (mtype = 0; mtype != MAXMAGIETYP; ++mtype) {
|
||||
if (strcmp(magic_school[mtype], type) == 0)
|
||||
|
@ -638,8 +638,14 @@ static int tolua_unit_get_familiar(lua_State * L)
|
|||
|
||||
static int tolua_unit_set_familiar(lua_State * L)
|
||||
{
|
||||
unit *self = (unit *)tolua_tousertype(L, 1, 0);
|
||||
create_newfamiliar(self, (unit *)tolua_tousertype(L, 2, 0));
|
||||
unit *mag = (unit *)tolua_tousertype(L, 1, NULL);
|
||||
unit *fam = (unit *)tolua_tousertype(L, 2, NULL);
|
||||
if (fam) {
|
||||
set_familiar(mag, fam);
|
||||
}
|
||||
else {
|
||||
remove_familiar(mag);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -747,7 +753,7 @@ static int tolua_unit_get_items(lua_State * L)
|
|||
static int tolua_unit_get_spells(lua_State * L)
|
||||
{
|
||||
unit *self = (unit *) tolua_tousertype(L, 1, 0);
|
||||
sc_mage *mage = self ? get_mage(self) : 0;
|
||||
sc_mage *mage = self ? get_mage_depr(self) : 0;
|
||||
spellbook *sb = mage ? mage->spellbook : 0;
|
||||
selist *slist = 0;
|
||||
if (sb) {
|
||||
|
|
|
@ -86,8 +86,7 @@ static void lc_done(struct attrib *a)
|
|||
free(data);
|
||||
}
|
||||
|
||||
static void
|
||||
lc_write(const struct attrib *a, const void *owner, struct storage *store)
|
||||
static void lc_write(const struct attrib *a, const void *owner, struct storage *store)
|
||||
{
|
||||
building_action *data = (building_action *)a->data.v;
|
||||
const char *fname = data->fname;
|
||||
|
@ -106,8 +105,7 @@ static int lc_read(struct attrib *a, void *owner, gamedata *data)
|
|||
building *b = (building *)owner;
|
||||
int result = 0;
|
||||
if (data->version < ATTRIBOWNER_VERSION) {
|
||||
result = read_reference(&b, data, read_building_reference, resolve_building);
|
||||
assert(b == owner);
|
||||
READ_INT(data->store, NULL);
|
||||
}
|
||||
READ_TOK(store, name, sizeof(name));
|
||||
if (strcmp(name, "tunnel_action") == 0) {
|
||||
|
|
132
src/creport.c
132
src/creport.c
|
@ -101,7 +101,6 @@ struct locale *crtag_locale(void) {
|
|||
|
||||
static const char *crtag(const char *key)
|
||||
{
|
||||
/* TODO: those locale lookups are shit, but static kills testing */
|
||||
const char *result;
|
||||
result = LOC(crtag_locale(), key);
|
||||
return result;
|
||||
|
@ -254,7 +253,7 @@ cr_output_curses(struct stream *out, const faction * viewer, const void *obj, ob
|
|||
}
|
||||
|
||||
while (a) {
|
||||
if (fval(a->type, ATF_CURSE)) {
|
||||
if (a->type == &at_curse) {
|
||||
curse *c = (curse *)a->data.v;
|
||||
message *msg;
|
||||
|
||||
|
@ -382,8 +381,8 @@ static int cr_skill(variant var, char *buffer, const void *userdata)
|
|||
UNUSED_ARG(userdata);
|
||||
if (sk != NOSKILL)
|
||||
sprintf(buffer, "\"%s\"",
|
||||
translate(mkname("skill", skillnames[sk]), skillname(sk,
|
||||
report->locale)));
|
||||
translate(mkname("skill", skillnames[sk]), skillname(sk,
|
||||
report->locale)));
|
||||
else
|
||||
strcpy(buffer, "\"\"");
|
||||
return 0;
|
||||
|
@ -426,7 +425,7 @@ static int cr_resources(variant var, char *buffer, const void *userdata)
|
|||
assert(name);
|
||||
wp +=
|
||||
sprintf(wp, "\"%d %s", rlist->number, translate(name, LOC(f->locale,
|
||||
name)));
|
||||
name)));
|
||||
for (;;) {
|
||||
rlist = rlist->next;
|
||||
if (rlist == NULL)
|
||||
|
@ -435,7 +434,7 @@ static int cr_resources(variant var, char *buffer, const void *userdata)
|
|||
assert(name);
|
||||
wp +=
|
||||
sprintf(wp, ", %d %s", rlist->number, translate(name,
|
||||
LOC(f->locale, name)));
|
||||
LOC(f->locale, name)));
|
||||
}
|
||||
strcat(wp, "\"");
|
||||
}
|
||||
|
@ -621,86 +620,106 @@ static void cr_output_messages(FILE * F, message_list * msgs, faction * f)
|
|||
}
|
||||
|
||||
/* prints a building */
|
||||
static void
|
||||
cr_output_building(FILE * F, building * b, const unit * owner, int fno,
|
||||
faction * f)
|
||||
static void cr_output_building(struct stream *out, building *b,
|
||||
const unit *owner, int fno, faction *f)
|
||||
{
|
||||
const char *bname, *billusion;
|
||||
|
||||
fprintf(F, "BURG %d\n", b->no);
|
||||
stream_printf(out, "BURG %d\n", b->no);
|
||||
|
||||
report_building(b, &bname, &billusion);
|
||||
if (billusion) {
|
||||
fprintf(F, "\"%s\";Typ\n", translate(billusion, LOC(f->locale,
|
||||
stream_printf(out, "\"%s\";Typ\n", translate(billusion, LOC(f->locale,
|
||||
billusion)));
|
||||
if (owner && owner->faction == f) {
|
||||
fprintf(F, "\"%s\";wahrerTyp\n", translate(bname, LOC(f->locale,
|
||||
stream_printf(out, "\"%s\";wahrerTyp\n", translate(bname, LOC(f->locale,
|
||||
bname)));
|
||||
}
|
||||
}
|
||||
else {
|
||||
fprintf(F, "\"%s\";Typ\n", translate(bname, LOC(f->locale, bname)));
|
||||
stream_printf(out, "\"%s\";Typ\n", translate(bname, LOC(f->locale, bname)));
|
||||
}
|
||||
stream_printf(out, "\"%s\";Name\n", b->name);
|
||||
if (b->display && b->display[0]) {
|
||||
stream_printf(out, "\"%s\";Beschr\n", b->display);
|
||||
}
|
||||
if (b->size) {
|
||||
stream_printf(out, "%d;Groesse\n", b->size);
|
||||
}
|
||||
fprintf(F, "\"%s\";Name\n", b->name);
|
||||
if (b->display && b->display[0])
|
||||
fprintf(F, "\"%s\";Beschr\n", b->display);
|
||||
if (b->size)
|
||||
fprintf(F, "%d;Groesse\n", b->size);
|
||||
if (owner) {
|
||||
fprintf(F, "%d;Besitzer\n", owner->no);
|
||||
stream_printf(out, "%d;Besitzer\n", owner->no);
|
||||
}
|
||||
if (fno >= 0)
|
||||
fprintf(F, "%d;Partei\n", fno);
|
||||
if (b->besieged)
|
||||
fprintf(F, "%d;Belagerer\n", b->besieged);
|
||||
cr_output_curses_compat(F, f, b, TYP_BUILDING);
|
||||
if (fno >= 0) {
|
||||
stream_printf(out, "%d;Partei\n", fno);
|
||||
}
|
||||
if (b->besieged) {
|
||||
stream_printf(out, "%d;Belagerer\n", b->besieged);
|
||||
}
|
||||
cr_output_curses(out, f, b, TYP_BUILDING);
|
||||
}
|
||||
|
||||
static void cr_output_building_compat(FILE *F, building *b,
|
||||
const unit *owner, int fno, faction *f)
|
||||
{
|
||||
/* TODO: eliminate this function */
|
||||
stream strm;
|
||||
fstream_init(&strm, F);
|
||||
cr_output_building(&strm, b, owner, fno, f);
|
||||
}
|
||||
|
||||
/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
|
||||
|
||||
/* prints a ship */
|
||||
static void
|
||||
cr_output_ship(FILE * F, const ship * sh, const unit * u, int fcaptain,
|
||||
const faction * f, const region * r)
|
||||
static void cr_output_ship(struct stream *out, const ship *sh, const unit *u,
|
||||
int fcaptain, const faction *f, const region *r)
|
||||
{
|
||||
int w = 0;
|
||||
assert(sh);
|
||||
fprintf(F, "SCHIFF %d\n", sh->no);
|
||||
fprintf(F, "\"%s\";Name\n", sh->name);
|
||||
stream_printf(out, "SCHIFF %d\n", sh->no);
|
||||
stream_printf(out, "\"%s\";Name\n", sh->name);
|
||||
if (sh->display && sh->display[0])
|
||||
fprintf(F, "\"%s\";Beschr\n", sh->display);
|
||||
fprintf(F, "\"%s\";Typ\n", translate(sh->type->_name,
|
||||
stream_printf(out, "\"%s\";Beschr\n", sh->display);
|
||||
stream_printf(out, "\"%s\";Typ\n", translate(sh->type->_name,
|
||||
LOC(f->locale, sh->type->_name)));
|
||||
fprintf(F, "%d;Groesse\n", sh->size);
|
||||
stream_printf(out, "%d;Groesse\n", sh->size);
|
||||
if (sh->damage) {
|
||||
int percent =
|
||||
(sh->damage * 100 + DAMAGE_SCALE - 1) / (sh->size * DAMAGE_SCALE);
|
||||
fprintf(F, "%d;Schaden\n", percent);
|
||||
stream_printf(out, "%d;Schaden\n", percent);
|
||||
}
|
||||
if (u) {
|
||||
fprintf(F, "%d;Kapitaen\n", u->no);
|
||||
stream_printf(out, "%d;Kapitaen\n", u->no);
|
||||
}
|
||||
if (fcaptain >= 0) {
|
||||
stream_printf(out, "%d;Partei\n", fcaptain);
|
||||
}
|
||||
if (fcaptain >= 0)
|
||||
fprintf(F, "%d;Partei\n", fcaptain);
|
||||
|
||||
/* calculate cargo */
|
||||
if (u && (u->faction == f || omniscient(f))) {
|
||||
int n = 0, p = 0;
|
||||
int mweight = shipcapacity(sh);
|
||||
getshipweight(sh, &n, &p);
|
||||
|
||||
fprintf(F, "%d;capacity\n", mweight);
|
||||
fprintf(F, "%d;cargo\n", n);
|
||||
fprintf(F, "%d;speed\n", shipspeed(sh, u));
|
||||
stream_printf(out, "%d;capacity\n", mweight);
|
||||
stream_printf(out, "%d;cargo\n", n);
|
||||
stream_printf(out, "%d;speed\n", shipspeed(sh, u));
|
||||
}
|
||||
/* shore */
|
||||
w = NODIRECTION;
|
||||
if (!fval(r->terrain, SEA_REGION))
|
||||
w = sh->coast;
|
||||
if (w != NODIRECTION)
|
||||
fprintf(F, "%d;Kueste\n", w);
|
||||
stream_printf(out, "%d;Kueste\n", w);
|
||||
|
||||
cr_output_curses_compat(F, f, sh, TYP_SHIP);
|
||||
cr_output_curses(out, f, sh, TYP_SHIP);
|
||||
}
|
||||
|
||||
static void cr_output_ship_compat(FILE *F, const ship *sh, const unit *u,
|
||||
int fcaptain, const faction *f, const region *r)
|
||||
{
|
||||
/* TODO: eliminate this function */
|
||||
stream strm;
|
||||
fstream_init(&strm, F);
|
||||
cr_output_ship(&strm, sh, u, fcaptain, f, r);
|
||||
}
|
||||
|
||||
static int stream_order(stream *out, const struct order *ord) {
|
||||
|
@ -798,11 +817,12 @@ void cr_output_unit(stream *out, const region * r, const faction * f,
|
|||
if (fother) {
|
||||
stream_printf(out, "%d;Anderepartei\n", fother->no);
|
||||
}
|
||||
} else if (!fval(u, UFL_ANON_FACTION)) {
|
||||
}
|
||||
else if (!fval(u, UFL_ANON_FACTION)) {
|
||||
/* OBS: anonymity overrides everything */
|
||||
/* we have no alliance, so we get duped */
|
||||
stream_printf(out, "%d;Partei\n", (fother ? fother : u->faction)->no);
|
||||
if (fother==f) {
|
||||
if (fother == f) {
|
||||
/* sieht aus wie unsere, ist es aber nicht. */
|
||||
stream_printf(out, "1;Verraeter\n");
|
||||
}
|
||||
|
@ -929,12 +949,12 @@ void cr_output_unit(stream *out, const region * r, const faction * f,
|
|||
}
|
||||
stream_printf(out, "%d %d;%s\n", u->number * level_days(sv->level), esk,
|
||||
translate(mkname("skill", skillnames[sk]), skillname(sk,
|
||||
f->locale)));
|
||||
f->locale)));
|
||||
}
|
||||
}
|
||||
|
||||
/* spells that this unit can cast */
|
||||
mage = get_mage(u);
|
||||
mage = get_mage_depr(u);
|
||||
if (mage) {
|
||||
int i, maxlevel = effskill(u, SK_MAGIC, 0);
|
||||
cr_output_spells(out, u, maxlevel);
|
||||
|
@ -944,7 +964,7 @@ void cr_output_unit(stream *out, const region * r, const faction * f,
|
|||
if (sp) {
|
||||
const char *name =
|
||||
translate(mkname("spell", sp->sname), spell_name(sp,
|
||||
f->locale));
|
||||
f->locale));
|
||||
stream_printf(out, "KAMPFZAUBER %d\n", i);
|
||||
stream_printf(out, "\"%s\";name\n", name);
|
||||
stream_printf(out, "%d;level\n", mage->combatspells[i].level);
|
||||
|
@ -1201,7 +1221,7 @@ void cr_output_resources(stream *out, const faction * f, const region *r, bool s
|
|||
if (result[n].number >= 0) {
|
||||
pos =
|
||||
cr_output_resource(pos, result[n].rtype, f->locale, result[n].number,
|
||||
result[n].level);
|
||||
result[n].level);
|
||||
}
|
||||
}
|
||||
if (pos != cbuf) {
|
||||
|
@ -1343,10 +1363,10 @@ static void cr_output_region(FILE * F, report_context * ctx, region * r)
|
|||
building *b;
|
||||
ship *sh;
|
||||
unit *u;
|
||||
int stealthmod = stealth_modifier(r->seen.mode);
|
||||
int stealthmod = stealth_modifier(r, f, r->seen.mode);
|
||||
|
||||
if (r->display && r->display[0])
|
||||
fprintf(F, "\"%s\";Beschr\n", r->display);
|
||||
if (r->land && r->land->display && r->land->display[0])
|
||||
fprintf(F, "\"%s\";Beschr\n", r->land->display);
|
||||
if (fval(r->terrain, LAND_REGION)) {
|
||||
assert(r->land);
|
||||
fprintf(F, "%d;Bauern\n", rpeasants(r));
|
||||
|
@ -1458,7 +1478,7 @@ static void cr_output_region(FILE * F, report_context * ctx, region * r)
|
|||
const faction *sf = visible_faction(f, u);
|
||||
fno = sf->no;
|
||||
}
|
||||
cr_output_building(F, b, u, fno, f);
|
||||
cr_output_building_compat(F, b, u, fno, f);
|
||||
}
|
||||
|
||||
/* ships */
|
||||
|
@ -1470,14 +1490,14 @@ static void cr_output_region(FILE * F, report_context * ctx, region * r)
|
|||
fno = sf->no;
|
||||
}
|
||||
|
||||
cr_output_ship(F, sh, u, fno, f, r);
|
||||
cr_output_ship_compat(F, sh, u, fno, f, r);
|
||||
}
|
||||
|
||||
/* visible units */
|
||||
for (u = r->units; u; u = u->next) {
|
||||
|
||||
if (u->building || u->ship || (stealthmod > INT_MIN
|
||||
&& cansee(f, r, u, stealthmod))) {
|
||||
&& cansee_ex(f, r, u, stealthmod, r->seen.mode))) {
|
||||
cr_output_unit_compat(F, r, f, u, r->seen.mode);
|
||||
}
|
||||
}
|
||||
|
@ -1516,7 +1536,7 @@ report_computer(const char *filename, report_context * ctx, const char *bom)
|
|||
|
||||
fprintf(F, "VERSION %d\n", C_REPORT_VERSION);
|
||||
fprintf(F, "\"UTF-8\";charset\n\"%s\";locale\n",
|
||||
locale_name(f->locale));
|
||||
locale_name(f->locale));
|
||||
fprintf(F, "%d;noskillpoints\n", 1);
|
||||
fprintf(F, "%lld;date\n", (long long)ctx->report_time);
|
||||
fprintf(F, "\"%s\";Spiel\n", game_name());
|
||||
|
@ -1683,7 +1703,7 @@ report_computer(const char *filename, report_context * ctx, const char *bom)
|
|||
}
|
||||
}
|
||||
report_crtypes(F, f->locale);
|
||||
if (f->locale!=crtag_locale()) {
|
||||
if (f->locale != crtag_locale()) {
|
||||
report_translations(F);
|
||||
}
|
||||
reset_translations();
|
||||
|
|
|
@ -266,7 +266,6 @@ void add_recruits(unit * u, int number, int wanted)
|
|||
|
||||
strlcpy(equipment, "new_", sizeof(equipment));
|
||||
strlcat(equipment, u_race(u)->_name, sizeof(equipment));
|
||||
strlcat(equipment, "_unit", sizeof(equipment));
|
||||
equip_unit(unew, get_equipment(equipment));
|
||||
|
||||
if (unew != u) {
|
||||
|
@ -661,7 +660,12 @@ static int forget_cmd(unit * u, order * ord)
|
|||
init_order(ord);
|
||||
s = gettoken(token, sizeof(token));
|
||||
|
||||
if ((sk = get_skill(s, u->faction->locale)) != NOSKILL) {
|
||||
sk = get_skill(s, u->faction->locale);
|
||||
if (sk != NOSKILL) {
|
||||
if (sk == SK_MAGIC && is_familiar(u)) {
|
||||
/* some units cannot forget their innate magical abilities */
|
||||
return 0;
|
||||
}
|
||||
ADDMSG(&u->faction->msgs, msg_message("forget", "unit skill", u, sk));
|
||||
set_level(u, sk, 0);
|
||||
}
|
||||
|
|
|
@ -2,6 +2,17 @@
|
|||
#include "settings.h"
|
||||
#include "eressea.h"
|
||||
|
||||
#include "calendar.h"
|
||||
#include "chaos.h"
|
||||
#include "items.h"
|
||||
#include "creport.h"
|
||||
#include "report.h"
|
||||
#include "names.h"
|
||||
#include "reports.h"
|
||||
#include "spells.h"
|
||||
#include "vortex.h"
|
||||
#include "wormhole.h"
|
||||
|
||||
#include <kernel/config.h>
|
||||
#include <util/log.h>
|
||||
|
||||
|
@ -25,16 +36,6 @@
|
|||
#include <util/message.h>
|
||||
#include <races/races.h>
|
||||
|
||||
#include "calendar.h"
|
||||
#include "chaos.h"
|
||||
#include "items.h"
|
||||
#include "creport.h"
|
||||
#include "report.h"
|
||||
#include "names.h"
|
||||
#include "reports.h"
|
||||
#include "spells.h"
|
||||
#include "wormhole.h"
|
||||
|
||||
void game_done(void)
|
||||
{
|
||||
#ifdef CLEANUP_CODE
|
||||
|
@ -53,6 +54,7 @@ void game_done(void)
|
|||
calendar_cleanup();
|
||||
free_functions();
|
||||
free_config();
|
||||
free_special_directions();
|
||||
free_locales();
|
||||
kernel_done();
|
||||
}
|
||||
|
|
|
@ -418,10 +418,12 @@ message * give_men(int n, unit * u, unit * u2, struct order *ord)
|
|||
set_racename(&u2->attribs, get_racename(u->attribs));
|
||||
u_setrace(u2, u_race(u));
|
||||
u2->irace = u->irace;
|
||||
if (fval(u, UFL_HERO))
|
||||
if (fval(u, UFL_HERO)) {
|
||||
fset(u2, UFL_HERO);
|
||||
else
|
||||
}
|
||||
else {
|
||||
freset(u2, UFL_HERO);
|
||||
}
|
||||
}
|
||||
|
||||
/* Einheiten von Schiffen können nicht NACH in von
|
||||
|
@ -589,7 +591,7 @@ void give_unit(unit * u, unit * u2, order * ord)
|
|||
cmistake(u, ord, 155, MSG_COMMERCE);
|
||||
return;
|
||||
}
|
||||
mage = get_mage(u);
|
||||
mage = get_mage_depr(u);
|
||||
if (!mage || u2->faction->magiegebiet != mage->magietyp) {
|
||||
cmistake(u, ord, 157, MSG_COMMERCE);
|
||||
return;
|
||||
|
|
|
@ -20,6 +20,7 @@ without prior permission by the authors of Eressea.
|
|||
#include <util/bsdstring.h>
|
||||
#include <util/event.h>
|
||||
#include <util/functions.h>
|
||||
#include <util/gamedata.h>
|
||||
#include <util/log.h>
|
||||
#include <util/parser.h>
|
||||
#include <util/resolve.h>
|
||||
|
@ -290,10 +291,10 @@ use_item_lua(unit *u, const item_type *itype, int amount, struct order *ord)
|
|||
}
|
||||
|
||||
/* compat code for old data files */
|
||||
static int caldera_read(trigger *t, struct gamedata *data)
|
||||
static int caldera_read(trigger *t, gamedata *data)
|
||||
{
|
||||
UNUSED_ARG(t);
|
||||
read_building_reference(data);
|
||||
READ_INT(data->store, NULL);
|
||||
return AT_READ_FAIL;
|
||||
}
|
||||
|
||||
|
|
|
@ -74,9 +74,9 @@ struct order *ord)
|
|||
if (amount > MAXGAIN) {
|
||||
amount = MAXGAIN;
|
||||
}
|
||||
teach->value += amount * STUDYDAYS;
|
||||
if (teach->value > MAXGAIN * STUDYDAYS) {
|
||||
teach->value = MAXGAIN * STUDYDAYS;
|
||||
teach->days += amount * STUDYDAYS;
|
||||
if (teach->days > MAXGAIN * STUDYDAYS) {
|
||||
teach->days = MAXGAIN * STUDYDAYS;
|
||||
}
|
||||
i_change(&u->items, itype, -amount);
|
||||
return 0;
|
||||
|
@ -145,7 +145,7 @@ struct order *ord)
|
|||
while (*ap && force > 0) {
|
||||
curse *c;
|
||||
attrib *a = *ap;
|
||||
if (!(a->type->flags & ATF_CURSE)) {
|
||||
if (a->type != &at_curse) {
|
||||
do {
|
||||
ap = &(*ap)->next;
|
||||
} while (*ap && a->type == (*ap)->type);
|
||||
|
|
|
@ -63,7 +63,7 @@ int *casualties)
|
|||
if (wp != NULL && wp->type == wtype)
|
||||
++k;
|
||||
}
|
||||
msg = msg_message("battle::useflamingsword", "amount unit", k, fi->unit);
|
||||
msg = msg_message("useflamingsword", "amount unit", k, fi->unit);
|
||||
message_all(fi->side->battle, msg);
|
||||
msg_release(msg);
|
||||
fi->catmsg = 0;
|
||||
|
@ -119,7 +119,7 @@ int *casualties)
|
|||
if (af->person[i].reload == 0 && af->person[i].missile == wp)
|
||||
++k;
|
||||
}
|
||||
msg = msg_message("battle::usecatapult", "amount unit", k, au);
|
||||
msg = msg_message("usecatapult", "amount unit", k, au);
|
||||
message_all(b, msg);
|
||||
msg_release(msg);
|
||||
af->catmsg = 0;
|
||||
|
|
|
@ -7,13 +7,40 @@
|
|||
#include "region.h"
|
||||
#include "group.h"
|
||||
#include "faction.h"
|
||||
#include "objtypes.h"
|
||||
#include "plane.h"
|
||||
|
||||
#include <util/attrib.h>
|
||||
#include <util/gamedata.h>
|
||||
|
||||
#include <storage.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
void read_allies(gamedata * data, faction *f)
|
||||
{
|
||||
ally **sfp = &f->allies;
|
||||
for (;;) {
|
||||
int aid;
|
||||
READ_INT(data->store, &aid);
|
||||
if (aid > 0) {
|
||||
ally * al = ally_add(sfp, NULL);
|
||||
int state;
|
||||
if ((al->faction = findfaction(aid)) == NULL) {
|
||||
ur_add(RESOLVE_FACTION | aid, (void **)&al->faction, NULL);
|
||||
}
|
||||
READ_INT(data->store, &state);
|
||||
al->status = state & HELP_ALL;
|
||||
sfp = &al->next;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ally * ally_find(ally *al, const struct faction *f) {
|
||||
for (; al; al = al->next) {
|
||||
if (al->faction == f) return al;
|
||||
|
|
|
@ -26,7 +26,9 @@ extern "C" {
|
|||
struct attrib_type;
|
||||
struct plane;
|
||||
struct faction;
|
||||
struct gamedata;
|
||||
struct unit;
|
||||
|
||||
extern struct attrib_type at_npcfaction;
|
||||
|
||||
typedef struct ally {
|
||||
|
@ -35,6 +37,7 @@ extern "C" {
|
|||
int status;
|
||||
} ally;
|
||||
|
||||
void read_allies(struct gamedata * data, struct faction *f);
|
||||
ally * ally_find(ally *al, const struct faction *f);
|
||||
ally * ally_add(ally **al_p, struct faction *f);
|
||||
void ally_remove(ally **al_p, struct faction *f);
|
||||
|
|
|
@ -991,6 +991,7 @@ void free_construction(struct construction *cons)
|
|||
{
|
||||
while (cons) {
|
||||
construction *next = cons->improvement;
|
||||
free(cons->name);
|
||||
free(cons->materials);
|
||||
free(cons);
|
||||
cons = next;
|
||||
|
|
|
@ -322,25 +322,26 @@ void write_building_reference(const struct building *b, struct storage *store)
|
|||
WRITE_INT(store, (b && b->region) ? b->no : 0);
|
||||
}
|
||||
|
||||
int resolve_building(variant id, void *address)
|
||||
void resolve_building(building *b)
|
||||
{
|
||||
int result = 0;
|
||||
building *b = NULL;
|
||||
if (id.i != 0) {
|
||||
b = findbuilding(id.i);
|
||||
if (b == NULL) {
|
||||
result = -1;
|
||||
}
|
||||
}
|
||||
*(building **)address = b;
|
||||
return result;
|
||||
resolve(RESOLVE_BUILDING | b->no, b);
|
||||
}
|
||||
|
||||
variant read_building_reference(gamedata * data)
|
||||
int read_building_reference(gamedata * data, building **bp, resolve_fun fun)
|
||||
{
|
||||
variant result;
|
||||
READ_INT(data->store, &result.i);
|
||||
return result;
|
||||
int id;
|
||||
READ_INT(data->store, &id);
|
||||
if (id > 0) {
|
||||
*bp = findbuilding(id);
|
||||
if (*bp == NULL) {
|
||||
*bp = NULL;
|
||||
ur_add(RESOLVE_BUILDING | id, (void**)bp, fun);
|
||||
}
|
||||
}
|
||||
else {
|
||||
*bp = NULL;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
building *new_building(const struct building_type * btype, region * r,
|
||||
|
|
|
@ -20,7 +20,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
#define H_KRNL_BUILDING
|
||||
|
||||
#include <kernel/types.h>
|
||||
#include <util/variant.h>
|
||||
#include <util/resolve.h>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
@ -152,10 +152,11 @@ extern "C" {
|
|||
#include "build.h"
|
||||
#define NOBUILDING NULL
|
||||
|
||||
int resolve_building(variant data, void *address);
|
||||
#define RESOLVE_BUILDING (TYP_BUILDING << 24)
|
||||
void resolve_building(building *b);
|
||||
void write_building_reference(const struct building *b,
|
||||
struct storage *store);
|
||||
variant read_building_reference(struct gamedata *data);
|
||||
int read_building_reference(struct gamedata * data, struct building **bp, resolve_fun fun);
|
||||
|
||||
struct building *findbuilding(int n);
|
||||
|
||||
|
|
|
@ -606,37 +606,26 @@ int read_borders(gamedata *data)
|
|||
{
|
||||
struct storage *store = data->store;
|
||||
for (;;) {
|
||||
int bid = 0;
|
||||
int fid, tid, bid;
|
||||
char zText[32];
|
||||
region *from, *to;
|
||||
border_type *type;
|
||||
|
||||
READ_TOK(store, zText, sizeof(zText));
|
||||
if (!strcmp(zText, "end"))
|
||||
if (!strcmp(zText, "end")) {
|
||||
break;
|
||||
}
|
||||
READ_INT(store, &bid);
|
||||
type = find_bordertype(zText);
|
||||
if (type == NULL) {
|
||||
log_error("[read_borders] connection %d type %s is not registered", bid, zText);
|
||||
assert(type || !"connection type not registered");
|
||||
}
|
||||
|
||||
READ_INT(store, &bid);
|
||||
if (data->version < UIDHASH_VERSION) {
|
||||
int fx, fy, tx, ty;
|
||||
READ_INT(store, &fx);
|
||||
READ_INT(store, &fy);
|
||||
READ_INT(store, &tx);
|
||||
READ_INT(store, &ty);
|
||||
from = findregion(fx, fy);
|
||||
to = findregion(tx, ty);
|
||||
}
|
||||
else {
|
||||
int fid, tid;
|
||||
READ_INT(store, &fid);
|
||||
READ_INT(store, &tid);
|
||||
from = findregionbyid(fid);
|
||||
to = findregionbyid(tid);
|
||||
}
|
||||
READ_INT(store, &fid);
|
||||
READ_INT(store, &tid);
|
||||
from = findregionbyid(fid);
|
||||
to = findregionbyid(tid);
|
||||
if (!to || !from) {
|
||||
log_error("%s connection %d has missing regions", zText, bid);
|
||||
if (type->read) {
|
||||
|
@ -660,19 +649,6 @@ int read_borders(gamedata *data)
|
|||
b->id = bid;
|
||||
assert(bid <= nextborder);
|
||||
type->read(b, data);
|
||||
if (data->version < NOBORDERATTRIBS_VERSION) {
|
||||
attrib *a = NULL;
|
||||
int result = read_attribs(data, &a, b);
|
||||
if (border_convert_cb) {
|
||||
border_convert_cb(b, a);
|
||||
}
|
||||
while (a) {
|
||||
a_remove(&a, a);
|
||||
}
|
||||
if (result < 0) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
if (!type->write) {
|
||||
log_warning("invalid border '%s' between '%s' and '%s'\n", zText, regionname(from, 0), regionname(to, 0));
|
||||
}
|
||||
|
|
|
@ -191,12 +191,7 @@ int curse_read(attrib * a, void *owner, gamedata *data)
|
|||
READ_INT(store, &c->duration);
|
||||
READ_FLT(store, &flt);
|
||||
c->vigour = flt;
|
||||
if (data->version < INTPAK_VERSION) {
|
||||
ur = resolve_unit(read_int(data->store), &c->magician);
|
||||
}
|
||||
else {
|
||||
ur = read_reference(&c->magician, data, read_unit_reference, resolve_unit);
|
||||
}
|
||||
ur = read_unit_reference(data, &c->magician, NULL);
|
||||
if (data->version < CURSEFLOAT_VERSION) {
|
||||
READ_INT(store, &n);
|
||||
c->effect = (float)n;
|
||||
|
@ -231,9 +226,7 @@ int curse_read(attrib * a, void *owner, gamedata *data)
|
|||
READ_INT(store, &c->data.i);
|
||||
}
|
||||
if (c->type->typ == CURSETYP_REGION) {
|
||||
int rr =
|
||||
read_reference(&c->data.v, data, read_region_reference,
|
||||
RESOLVE_REGION(data->version));
|
||||
int rr = read_region_reference(data, (region **)&c->data.v, NULL);
|
||||
if (ur == 0 && rr == 0 && !c->data.v) {
|
||||
return AT_READ_FAIL;
|
||||
}
|
||||
|
@ -273,8 +266,7 @@ attrib_type at_curse = {
|
|||
curse_age,
|
||||
curse_write,
|
||||
curse_read,
|
||||
NULL,
|
||||
ATF_CURSE
|
||||
NULL
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
|
@ -363,7 +355,7 @@ void ct_checknames(void) {
|
|||
static bool cmp_curse(const attrib * a, const void *data)
|
||||
{
|
||||
const curse *c = (const curse *)data;
|
||||
if (a->type->flags & ATF_CURSE) {
|
||||
if (a->type == &at_curse) {
|
||||
if (!data || c == (curse *)a->data.v)
|
||||
return true;
|
||||
}
|
||||
|
@ -375,7 +367,7 @@ curse *get_curse(attrib * ap, const curse_type * ctype)
|
|||
attrib *a = ap;
|
||||
if (!ctype) return NULL;
|
||||
while (a) {
|
||||
if (a->type->flags & ATF_CURSE) {
|
||||
if (a->type == &at_curse) {
|
||||
const attrib_type *at = a->type;
|
||||
while (a && a->type == at) {
|
||||
curse *c = (curse *)a->data.v;
|
||||
|
@ -710,7 +702,7 @@ bool is_cursed_with(const attrib * ap, const curse * c)
|
|||
const attrib *a = ap;
|
||||
|
||||
while (a) {
|
||||
if ((a->type->flags & ATF_CURSE) && (c == (const curse *)a->data.v)) {
|
||||
if ((a->type == &at_curse) && (c == (const curse *)a->data.v)) {
|
||||
return true;
|
||||
}
|
||||
a = a->next;
|
||||
|
|
|
@ -311,9 +311,6 @@ extern "C" {
|
|||
#define get_curseeffect(a, ctype) \
|
||||
curse_geteffect(get_curse(a, ctype))
|
||||
|
||||
/* eressea-defined attribute-type flags */
|
||||
#define ATF_CURSE ATF_USER_DEFINED
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -29,6 +29,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
|
||||
/* util includes */
|
||||
#include <selist.h>
|
||||
#include <critbit.h>
|
||||
#include <util/log.h>
|
||||
#include <util/rand.h>
|
||||
#include <util/rng.h>
|
||||
|
||||
|
@ -37,43 +39,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static equipment *equipment_sets;
|
||||
|
||||
equipment *get_or_create_equipment(const char *eqname)
|
||||
{
|
||||
equipment **eqp = &equipment_sets;
|
||||
for (;;) {
|
||||
struct equipment *eq = *eqp;
|
||||
int i = eq ? strcmp(eq->name, eqname) : 1;
|
||||
if (i > 0) {
|
||||
eq = (equipment *)calloc(1, sizeof(equipment));
|
||||
eq->name = strdup(eqname);
|
||||
eq->next = *eqp;
|
||||
memset(eq->skills, 0, sizeof(eq->skills));
|
||||
*eqp = eq;
|
||||
break;
|
||||
}
|
||||
else if (i == 0) {
|
||||
break;
|
||||
}
|
||||
eqp = &eq->next;
|
||||
}
|
||||
return *eqp;
|
||||
}
|
||||
|
||||
equipment *get_equipment(const char *eqname)
|
||||
{
|
||||
equipment *eq = equipment_sets;
|
||||
for (; eq; eq = eq->next) {
|
||||
int i = strcmp(eq->name, eqname);
|
||||
if (i == 0)
|
||||
return eq;
|
||||
else if (i > 0)
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void equipment_setskill(equipment * eq, skill_t sk, const char *value)
|
||||
{
|
||||
if (eq != NULL) {
|
||||
|
@ -156,7 +121,7 @@ void equip_unit_mask(struct unit *u, const struct equipment *eq, int mask)
|
|||
if (eq->spells) {
|
||||
selist * ql = eq->spells;
|
||||
int qi;
|
||||
sc_mage * mage = get_mage(u);
|
||||
sc_mage * mage = get_mage_depr(u);
|
||||
|
||||
for (qi = 0; ql; selist_advance(&ql, &qi, 1)) {
|
||||
lazy_spell *sbe = (lazy_spell *)selist_get(ql, qi);
|
||||
|
@ -236,27 +201,111 @@ void free_ls(void *arg) {
|
|||
free(ls);
|
||||
}
|
||||
|
||||
void equipment_done(void) {
|
||||
equipment **eqp = &equipment_sets;
|
||||
while (*eqp) {
|
||||
int i;
|
||||
equipment *eq = *eqp;
|
||||
*eqp = eq->next;
|
||||
free(eq->name);
|
||||
if (eq->spells) {
|
||||
selist_foreach(eq->spells, free_ls);
|
||||
selist_free(eq->spells);
|
||||
}
|
||||
while (eq->items) {
|
||||
itemdata *next = eq->items->next;
|
||||
free(eq->items->value);
|
||||
free(eq->items);
|
||||
eq->items = next;
|
||||
}
|
||||
/* TODO: subsets, skills */
|
||||
for (i=0;i!=MAXSKILLS;++i) {
|
||||
free(eq->skills[i]);
|
||||
}
|
||||
free(eq);
|
||||
static critbit_tree cb_equipments = { 0 };
|
||||
|
||||
#define EQNAMELEN 24
|
||||
|
||||
typedef struct eq_entry {
|
||||
char key[EQNAMELEN];
|
||||
equipment *value;
|
||||
} eq_entry;
|
||||
|
||||
typedef struct name_cb_data {
|
||||
const equipment *find;
|
||||
const char *result;
|
||||
} name_cb_data;
|
||||
|
||||
|
||||
static int equipment_name_cb(const void * match, const void * key, size_t keylen, void *cbdata) {
|
||||
const eq_entry *ent = (const eq_entry *)match;
|
||||
name_cb_data *query = (name_cb_data *)cbdata;
|
||||
if (ent->value == query->find) {
|
||||
query->result = ent->key;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *equipment_name(const struct equipment *eq)
|
||||
{
|
||||
name_cb_data data;
|
||||
|
||||
data.find = eq;
|
||||
data.result = NULL;
|
||||
cb_foreach(&cb_equipments, "", 0, equipment_name_cb, &data);
|
||||
return data.result;
|
||||
}
|
||||
|
||||
equipment *get_equipment(const char *eqname)
|
||||
{
|
||||
const void *match;
|
||||
|
||||
if (strlen(eqname) >= EQNAMELEN) {
|
||||
log_warning("equipment name is longer than %d bytes: %s", EQNAMELEN - 1, eqname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
match = cb_find_str(&cb_equipments, eqname);
|
||||
if (match) {
|
||||
const eq_entry *ent = (const eq_entry *)match;
|
||||
return ent->value;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
equipment *create_equipment(const char *eqname)
|
||||
{
|
||||
size_t len = strlen(eqname);
|
||||
eq_entry ent;
|
||||
|
||||
if (len >= EQNAMELEN) {
|
||||
log_error("equipment name is longer than %d bytes: %s", EQNAMELEN-1, eqname);
|
||||
len = EQNAMELEN-1;
|
||||
}
|
||||
memset(ent.key, 0, EQNAMELEN);
|
||||
memcpy(ent.key, eqname, len);
|
||||
|
||||
ent.value = (equipment *)calloc(1, sizeof(equipment));
|
||||
|
||||
cb_insert(&cb_equipments, &ent, sizeof(ent));
|
||||
return ent.value;
|
||||
}
|
||||
|
||||
equipment *get_or_create_equipment(const char *eqname)
|
||||
{
|
||||
equipment *eq = get_equipment(eqname);
|
||||
if (!eq) {
|
||||
return create_equipment(eqname);
|
||||
}
|
||||
return eq;
|
||||
}
|
||||
|
||||
static void free_equipment(equipment *eq) {
|
||||
int i;
|
||||
if (eq->spells) {
|
||||
selist_foreach(eq->spells, free_ls);
|
||||
selist_free(eq->spells);
|
||||
}
|
||||
while (eq->items) {
|
||||
itemdata *next = eq->items->next;
|
||||
free(eq->items->value);
|
||||
free(eq->items);
|
||||
eq->items = next;
|
||||
}
|
||||
/* TODO: subsets, skills */
|
||||
for (i = 0; i != MAXSKILLS; ++i) {
|
||||
free(eq->skills[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static int free_equipment_cb(const void * match, const void * key, size_t keylen, void *cbdata) {
|
||||
const eq_entry * ent = (const eq_entry *)match;
|
||||
free_equipment(ent->value);
|
||||
free(ent->value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void equipment_done(void) {
|
||||
cb_foreach(&cb_equipments, "", 0, free_equipment_cb, 0);
|
||||
cb_clear(&cb_equipments);
|
||||
}
|
||||
|
|
|
@ -45,19 +45,19 @@ extern "C" {
|
|||
} subset;
|
||||
|
||||
typedef struct equipment {
|
||||
char *name;
|
||||
struct itemdata *items;
|
||||
char *skills[MAXSKILLS];
|
||||
struct selist *spells;
|
||||
struct subset *subsets;
|
||||
struct equipment *next;
|
||||
void(*callback) (const struct equipment *, struct unit *);
|
||||
} equipment;
|
||||
|
||||
void equipment_done(void);
|
||||
|
||||
const char *equipment_name(const struct equipment *eq);
|
||||
struct equipment *get_or_create_equipment(const char *eqname);
|
||||
struct equipment *get_equipment(const char *eqname);
|
||||
struct equipment *create_equipment(const char *eqname);
|
||||
|
||||
void equipment_setitem(struct equipment *eq,
|
||||
const struct item_type *itype, const char *value);
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include <CuTest.h>
|
||||
#include <tests.h>
|
||||
|
||||
void test_equipment(CuTest * tc)
|
||||
static void test_equipment(CuTest * tc)
|
||||
{
|
||||
equipment * eq;
|
||||
unit * u;
|
||||
|
@ -39,16 +39,40 @@ void test_equipment(CuTest * tc)
|
|||
CuAssertIntEquals(tc, 1, i_get(u->items, it_horses));
|
||||
CuAssertIntEquals(tc, 5, get_level(u, SK_MAGIC));
|
||||
|
||||
mage = get_mage(u);
|
||||
mage = get_mage_depr(u);
|
||||
CuAssertPtrNotNull(tc, mage);
|
||||
CuAssertPtrNotNull(tc, mage->spellbook);
|
||||
CuAssertTrue(tc, u_hasspell(u, sp));
|
||||
test_cleanup();
|
||||
}
|
||||
|
||||
static void test_get_equipment(CuTest * tc)
|
||||
{
|
||||
equipment * eq;
|
||||
|
||||
test_setup();
|
||||
eq = create_equipment("catapultammo123");
|
||||
CuAssertPtrNotNull(tc, eq);
|
||||
CuAssertStrEquals(tc, "catapultammo123", equipment_name(eq));
|
||||
eq = get_equipment("catapultammo123");
|
||||
CuAssertPtrNotNull(tc, eq);
|
||||
CuAssertStrEquals(tc, "catapultammo123", equipment_name(eq));
|
||||
eq = get_equipment("catapult");
|
||||
CuAssertPtrEquals(tc, NULL, eq);
|
||||
eq = create_equipment("catapult");
|
||||
eq = get_equipment("catapult");
|
||||
CuAssertPtrNotNull(tc, eq);
|
||||
CuAssertStrEquals(tc, "catapult", equipment_name(eq));
|
||||
eq = get_equipment("catapultammo123");
|
||||
CuAssertPtrNotNull(tc, eq);
|
||||
CuAssertStrEquals(tc, "catapultammo123", equipment_name(eq));
|
||||
test_cleanup();
|
||||
}
|
||||
|
||||
CuSuite *get_equipment_suite(void)
|
||||
{
|
||||
CuSuite *suite = CuSuiteNew();
|
||||
SUITE_ADD_TEST(suite, test_equipment);
|
||||
SUITE_ADD_TEST(suite, test_get_equipment);
|
||||
return suite;
|
||||
}
|
||||
|
|
|
@ -203,21 +203,6 @@ const char *factionname(const faction * f)
|
|||
return ibuf;
|
||||
}
|
||||
|
||||
int resolve_faction(variant id, void *address)
|
||||
{
|
||||
int result = 0;
|
||||
faction *f = NULL;
|
||||
if (id.i != 0) {
|
||||
f = findfaction(id.i);
|
||||
if (f == NULL) {
|
||||
result = -1;
|
||||
}
|
||||
}
|
||||
assert(address);
|
||||
*(faction **)address = f;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool faction_id_is_unused(int id)
|
||||
{
|
||||
return findfaction(id) == NULL;
|
||||
|
@ -332,10 +317,25 @@ bool checkpasswd(const faction * f, const char *passwd)
|
|||
return true;
|
||||
}
|
||||
|
||||
variant read_faction_reference(gamedata * data)
|
||||
void resolve_faction(faction *f)
|
||||
{
|
||||
variant id;
|
||||
READ_INT(data->store, &id.i);
|
||||
resolve(RESOLVE_FACTION | f->no, f);
|
||||
}
|
||||
|
||||
int read_faction_reference(gamedata * data, faction **fp, resolve_fun fun)
|
||||
{
|
||||
int id;
|
||||
READ_INT(data->store, &id);
|
||||
if (id > 0) {
|
||||
*fp = findfaction(id);
|
||||
if (*fp == NULL) {
|
||||
*fp = NULL;
|
||||
ur_add(RESOLVE_FACTION | id, (void **)fp, fun);
|
||||
}
|
||||
}
|
||||
else {
|
||||
*fp = NULL;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
|
||||
#include "skill.h"
|
||||
#include "types.h"
|
||||
|
||||
#include <util/resolve.h>
|
||||
#include <modules/score.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -126,8 +129,10 @@ extern "C" {
|
|||
|
||||
void write_faction_reference(const struct faction *f,
|
||||
struct storage *store);
|
||||
variant read_faction_reference(struct gamedata *data);
|
||||
int resolve_faction(variant data, void *addr);
|
||||
int read_faction_reference(struct gamedata *data, struct faction **fp, resolve_fun fun);
|
||||
|
||||
#define RESOLVE_FACTION (TYP_FACTION << 24)
|
||||
void resolve_faction(struct faction *f);
|
||||
|
||||
void renumber_faction(faction * f, int no);
|
||||
void free_factions(void);
|
||||
|
|
|
@ -24,6 +24,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
#include "ally.h"
|
||||
#include "faction.h"
|
||||
#include "unit.h"
|
||||
#include "objtypes.h"
|
||||
|
||||
/* attrib includes */
|
||||
#include <attributes/raceprefix.h>
|
||||
|
@ -238,16 +239,16 @@ void read_groups(gamedata *data, faction * f)
|
|||
g = new_group(f, buf, gid);
|
||||
pa = &g->allies;
|
||||
for (;;) {
|
||||
ally *a;
|
||||
variant fid;
|
||||
|
||||
fid = read_faction_reference(data);
|
||||
if (fid.i <= 0)
|
||||
break;
|
||||
a = ally_add(pa, findfaction(fid.i));
|
||||
READ_INT(store, &a->status);
|
||||
if (!a->faction)
|
||||
ur_add(fid, &a->faction, resolve_faction);
|
||||
ally *al;
|
||||
int id;
|
||||
READ_INT(store, &id);
|
||||
if (id == 0) break;
|
||||
al = ally_add(pa, NULL);
|
||||
al->faction = findfaction(id);
|
||||
if (!al->faction) {
|
||||
ur_add(RESOLVE_FACTION | id, (void **)&al->faction, NULL);
|
||||
}
|
||||
READ_INT(store, &al->status);
|
||||
}
|
||||
read_attribs(data, &g->attribs, g);
|
||||
}
|
||||
|
|
|
@ -60,6 +60,12 @@ static critbit_tree cb_resources;
|
|||
luxury_type *luxurytypes;
|
||||
potion_type *potiontypes;
|
||||
|
||||
#define RTYPENAMELEN 24
|
||||
typedef struct rt_entry {
|
||||
char key[RTYPENAMELEN];
|
||||
struct resource_type *value;
|
||||
} rt_entry;
|
||||
|
||||
static int res_changeaura(unit * u, const resource_type * rtype, int delta)
|
||||
{
|
||||
assert(rtype != NULL);
|
||||
|
@ -166,13 +172,19 @@ static int num_resources;
|
|||
|
||||
static void rt_register(resource_type * rtype)
|
||||
{
|
||||
char buffer[64];
|
||||
const char * name = rtype->_name;
|
||||
size_t len = strlen(name);
|
||||
rt_entry ent;
|
||||
|
||||
assert(len < sizeof(buffer) - sizeof(rtype));
|
||||
len = cb_new_kv(name, len, &rtype, sizeof(rtype), buffer);
|
||||
cb_insert(&cb_resources, buffer, len);
|
||||
if (len >= RTYPENAMELEN) {
|
||||
log_error("resource name is longer than %d bytes: %s",
|
||||
RTYPENAMELEN-1, name);
|
||||
len = RTYPENAMELEN-1;
|
||||
}
|
||||
ent.value = rtype;
|
||||
memset(ent.key, 0, RTYPENAMELEN);
|
||||
memcpy(ent.key, name, len);
|
||||
cb_insert(&cb_resources, &ent, sizeof(ent));
|
||||
++num_resources;
|
||||
}
|
||||
|
||||
|
@ -186,22 +198,11 @@ resource_type *rt_get_or_create(const char *name) {
|
|||
else {
|
||||
rtype->_name = strdup(name);
|
||||
rt_register(rtype);
|
||||
return rt_find(name);
|
||||
}
|
||||
}
|
||||
return rtype;
|
||||
}
|
||||
|
||||
static void it_register(item_type * itype)
|
||||
{
|
||||
char buffer[64];
|
||||
const char * name = itype->rtype->_name;
|
||||
size_t len = strlen(name);
|
||||
|
||||
assert(len < sizeof(buffer) - sizeof(itype));
|
||||
len = cb_new_kv(name, len, &itype, sizeof(itype), buffer);
|
||||
}
|
||||
|
||||
static const char *it_aliases[][2] = {
|
||||
{ "Runenschwert", "runesword" },
|
||||
{ "p12", "truthpotion" },
|
||||
|
@ -244,7 +245,6 @@ item_type *it_get_or_create(resource_type *rtype) {
|
|||
rtype->uchange = res_changeitem;
|
||||
rtype->itype = itype;
|
||||
rtype->flags |= RTF_ITEM;
|
||||
it_register(itype);
|
||||
return itype;
|
||||
}
|
||||
|
||||
|
@ -389,13 +389,20 @@ const potion_type *resource2potion(const resource_type * rtype)
|
|||
|
||||
resource_type *rt_find(const char *name)
|
||||
{
|
||||
void * match;
|
||||
resource_type *result = 0;
|
||||
const void *match;
|
||||
size_t len = strlen(name);
|
||||
|
||||
if (cb_find_prefix(&cb_resources, name, strlen(name) + 1, &match, 1, 0)) {
|
||||
cb_get_kv(match, &result, sizeof(result));
|
||||
if (len >= RTYPENAMELEN) {
|
||||
log_warning("resource name is longer than %d bytes: %s",
|
||||
RTYPENAMELEN-1, name);
|
||||
return NULL;
|
||||
}
|
||||
return result;
|
||||
match = cb_find_str(&cb_resources, name);
|
||||
if (match) {
|
||||
const rt_entry *ent = (const rt_entry *)match;
|
||||
return ent->value;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
item **i_find(item ** i, const item_type * it)
|
||||
|
@ -517,6 +524,7 @@ static int icache_size;
|
|||
#define ICACHE_MAX 100
|
||||
|
||||
void item_done(void) {
|
||||
icache_size = ICACHE_MAX;
|
||||
i_freeall(&icache);
|
||||
icache_size = 0;
|
||||
}
|
||||
|
@ -791,14 +799,14 @@ int change_money(unit * u, int v)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int add_resourcename_cb(const void * match, const void * key, size_t keylen, void *data)
|
||||
static int add_resourcename_cb(const void * match, const void * key,
|
||||
size_t keylen, void *data)
|
||||
{
|
||||
struct locale * lang = (struct locale *)data;
|
||||
int i = locale_index(lang);
|
||||
critbit_tree * cb = rnames + i;
|
||||
resource_type *rtype;
|
||||
resource_type *rtype = ((rt_entry *)match)->value;
|
||||
|
||||
cb_get_kv(match, &rtype, sizeof(rtype));
|
||||
for (i = 0; i != 2; ++i) {
|
||||
char buffer[128];
|
||||
const char * name = LOC(lang, resourcename(rtype, (i == 0) ? 0 : NMF_PLURAL));
|
||||
|
@ -834,20 +842,20 @@ const resource_type *findresourcetype(const char *name, const struct locale *lan
|
|||
else {
|
||||
log_debug("findresourcetype: transliterate failed for '%s'\n", name);
|
||||
}
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
attrib_type at_showitem = {
|
||||
"showitem"
|
||||
};
|
||||
|
||||
static int add_itemname_cb(const void * match, const void * key, size_t keylen, void *data)
|
||||
static int add_itemname_cb(const void * match, const void * key,
|
||||
size_t keylen, void *data)
|
||||
{
|
||||
struct locale * lang = (struct locale *)data;
|
||||
critbit_tree * cb = inames + locale_index(lang);
|
||||
resource_type *rtype;
|
||||
resource_type *rtype = ((rt_entry *)match)->value;
|
||||
|
||||
cb_get_kv(match, &rtype, sizeof(rtype));
|
||||
if (rtype->itype) {
|
||||
int i;
|
||||
for (i = 0; i != 2; ++i) {
|
||||
|
@ -951,7 +959,7 @@ void write_items(struct storage *store, item * ilist)
|
|||
|
||||
static void free_itype(item_type *itype) {
|
||||
assert(itype);
|
||||
free(itype->construction);
|
||||
free_construction(itype->construction);
|
||||
free(itype->_appearance[0]);
|
||||
free(itype->_appearance[1]);
|
||||
free(itype);
|
||||
|
@ -979,9 +987,10 @@ void free_rtype(resource_type *rtype) {
|
|||
free(rtype);
|
||||
}
|
||||
|
||||
int free_rtype_cb(const void * match, const void * key, size_t keylen, void *cbdata) {
|
||||
resource_type *rtype;
|
||||
cb_get_kv(match, &rtype, sizeof(rtype));
|
||||
static int free_rtype_cb(const void * match, const void * key,
|
||||
size_t keylen, void *cbdata)
|
||||
{
|
||||
resource_type *rtype = ((rt_entry *)match)->value;;
|
||||
free_rtype(rtype);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -173,12 +173,31 @@ static void test_core_resources(CuTest *tc) {
|
|||
test_cleanup();
|
||||
}
|
||||
|
||||
static void test_get_resource(CuTest *tc) {
|
||||
resource_type *rtype;
|
||||
|
||||
test_setup();
|
||||
|
||||
CuAssertPtrEquals(tc, NULL, rt_find("catapultammo123"));
|
||||
rtype = rt_get_or_create("catapultammo123");
|
||||
CuAssertPtrNotNull(tc, rtype);
|
||||
CuAssertPtrEquals(tc, rtype, rt_find("catapultammo123"));
|
||||
CuAssertStrEquals(tc, "catapultammo123", rtype->_name);
|
||||
|
||||
CuAssertPtrEquals(tc, NULL, rt_find("catapult"));
|
||||
rtype = rt_get_or_create("catapult");
|
||||
CuAssertPtrEquals(tc, rtype, rt_find("catapult"));
|
||||
CuAssertStrEquals(tc, "catapult", rtype->_name);
|
||||
test_cleanup();
|
||||
}
|
||||
|
||||
CuSuite *get_item_suite(void)
|
||||
{
|
||||
CuSuite *suite = CuSuiteNew();
|
||||
SUITE_ADD_TEST(suite, test_resourcename_no_appearance);
|
||||
SUITE_ADD_TEST(suite, test_resourcename_with_appearance);
|
||||
SUITE_ADD_TEST(suite, test_change_item);
|
||||
SUITE_ADD_TEST(suite, test_get_resource);
|
||||
SUITE_ADD_TEST(suite, test_resource_type);
|
||||
SUITE_ADD_TEST(suite, test_finditemtype);
|
||||
SUITE_ADD_TEST(suite, test_findresourcetype);
|
||||
|
|
|
@ -83,7 +83,7 @@ struct message *msg_feedback(const struct unit *u, struct order *ord,
|
|||
variant var;
|
||||
memset(args, 0, sizeof(args));
|
||||
|
||||
if (ord && ord->_noerror) {
|
||||
if (ord && is_silent(ord)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -46,10 +46,10 @@ extern "C" {
|
|||
int level;
|
||||
} msglevel;
|
||||
|
||||
extern struct message *msg_message(const char *name, const char *sig, ...);
|
||||
extern struct message *msg_feedback(const struct unit *, struct order *cmd,
|
||||
struct message *msg_message(const char *name, const char *sig, ...);
|
||||
struct message *msg_feedback(const struct unit *, struct order *cmd,
|
||||
const char *name, const char *sig, ...);
|
||||
extern struct message *add_message(struct message_list **pm,
|
||||
struct message *add_message(struct message_list **pm,
|
||||
struct message *m);
|
||||
void addmessage(struct region *r, struct faction *f, const char *s,
|
||||
msg_t mtype, int level);
|
||||
|
|
|
@ -79,8 +79,8 @@ static void test_noerror(CuTest *tc) {
|
|||
lang = test_create_locale();
|
||||
u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL));
|
||||
u->thisorder = parse_order("!@move", lang);
|
||||
CuAssertTrue(tc, u->thisorder->_persistent);
|
||||
CuAssertTrue(tc, u->thisorder->_noerror);
|
||||
CuAssertIntEquals(tc, K_MOVE | CMD_QUIET | CMD_PERSIST, u->thisorder->command);
|
||||
CuAssertTrue(tc, !is_persistent(u->thisorder));
|
||||
CuAssertPtrEquals(tc, NULL, msg_error(u, u->thisorder, 100));
|
||||
CuAssertPtrEquals(tc, NULL, msg_feedback(u, u->thisorder, "error_unit_not_found", NULL));
|
||||
test_cleanup();
|
||||
|
|
|
@ -30,12 +30,12 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
# define ORD_KEYWORD(ord) (ord)->data->_keyword
|
||||
# define ORD_KEYWORD(ord) (keyword_t)((ord)->command & 0xFFFF)
|
||||
# define ORD_LOCALE(ord) locale_array[(ord)->data->_lindex]->lang
|
||||
# define ORD_STRING(ord) (ord)->data->_str
|
||||
|
||||
typedef struct locale_data {
|
||||
struct order_data *short_orders[MAXKEYWORDS];
|
||||
struct order_data *short_orders;
|
||||
struct order_data *study_orders[MAXSKILLS];
|
||||
const struct locale *lang;
|
||||
} locale_data;
|
||||
|
@ -46,7 +46,6 @@ typedef struct order_data {
|
|||
const char *_str;
|
||||
int _refcount;
|
||||
int _lindex;
|
||||
keyword_t _keyword;
|
||||
} order_data;
|
||||
|
||||
static void release_data(order_data * data)
|
||||
|
@ -94,7 +93,7 @@ char* get_command(const order *ord, char *sbuffer, size_t size) {
|
|||
keyword_t kwd = ORD_KEYWORD(ord);
|
||||
int bytes;
|
||||
|
||||
if (ord->_noerror) {
|
||||
if (ord->command & CMD_QUIET) {
|
||||
if (size > 0) {
|
||||
*bufp++ = '!';
|
||||
--size;
|
||||
|
@ -103,7 +102,7 @@ char* get_command(const order *ord, char *sbuffer, size_t size) {
|
|||
WARN_STATIC_BUFFER();
|
||||
}
|
||||
}
|
||||
if (ord->_persistent) {
|
||||
if (ord->command & CMD_PERSIST) {
|
||||
if (size > 0) {
|
||||
*bufp++ = '@';
|
||||
--size;
|
||||
|
@ -162,8 +161,7 @@ order *copy_order(const order * src)
|
|||
if (src != NULL) {
|
||||
order *ord = (order *)malloc(sizeof(order));
|
||||
ord->next = NULL;
|
||||
ord->_persistent = src->_persistent;
|
||||
ord->_noerror = src->_noerror;
|
||||
ord->command = src->command;
|
||||
ord->data = src->data;
|
||||
++ord->data->_refcount;
|
||||
return ord;
|
||||
|
@ -189,13 +187,12 @@ void free_orders(order ** olist)
|
|||
}
|
||||
}
|
||||
|
||||
static char *mkdata(order_data **pdata, size_t len, keyword_t kwd, int lindex, const char *str)
|
||||
static char *mkdata(order_data **pdata, size_t len, int lindex, const char *str)
|
||||
{
|
||||
order_data *data;
|
||||
char *result;
|
||||
data = malloc(sizeof(order_data) + len + 1);
|
||||
result = (char *)(data + 1);
|
||||
data->_keyword = kwd;
|
||||
data->_lindex = lindex;
|
||||
data->_refcount = 0;
|
||||
data->_str = 0;
|
||||
|
@ -229,7 +226,7 @@ static order_data *create_data(keyword_t kwd, const char *sptr, int lindex)
|
|||
const char *skname = skillname(sk, lang);
|
||||
const char *spc = strchr(skname, ' ');
|
||||
size_t len = strlen(skname);
|
||||
char *dst = mkdata(&data, len + (spc ? 3 : 0), kwd, lindex, spc ? 0 : skname);
|
||||
char *dst = mkdata(&data, len + (spc ? 3 : 0), lindex, spc ? 0 : skname);
|
||||
locale_array[lindex]->study_orders[sk] = data;
|
||||
if (spc) {
|
||||
dst[0] = '\"';
|
||||
|
@ -246,26 +243,24 @@ static order_data *create_data(keyword_t kwd, const char *sptr, int lindex)
|
|||
|
||||
/* orders with no parameter, only one order_data per order required */
|
||||
else if (kwd != NOKEYWORD && *sptr == 0) {
|
||||
data = locale_array[lindex]->short_orders[kwd];
|
||||
data = locale_array[lindex]->short_orders;
|
||||
if (data == NULL) {
|
||||
mkdata(&data, 0, kwd, lindex, 0);
|
||||
mkdata(&data, 0, lindex, 0);
|
||||
data->_refcount = 1;
|
||||
locale_array[lindex]->short_orders[kwd] = data;
|
||||
locale_array[lindex]->short_orders = data;
|
||||
}
|
||||
++data->_refcount;
|
||||
return data;
|
||||
}
|
||||
mkdata(&data, s ? strlen(s) : 0, kwd, lindex, s);
|
||||
mkdata(&data, s ? strlen(s) : 0, lindex, s);
|
||||
data->_refcount = 1;
|
||||
return data;
|
||||
}
|
||||
|
||||
static void clear_localedata(int lindex) {
|
||||
int i;
|
||||
for (i = 0; i != MAXKEYWORDS; ++i) {
|
||||
release_data(locale_array[lindex]->short_orders[i]);
|
||||
locale_array[lindex]->short_orders[i] = 0;
|
||||
}
|
||||
release_data(locale_array[lindex]->short_orders);
|
||||
locale_array[lindex]->short_orders = NULL;
|
||||
for (i = 0; i != MAXSKILLS; ++i) {
|
||||
release_data(locale_array[lindex]->study_orders[i]);
|
||||
locale_array[lindex]->study_orders[i] = 0;
|
||||
|
@ -284,12 +279,12 @@ void close_orders(void) {
|
|||
}
|
||||
}
|
||||
|
||||
static order *create_order_i(keyword_t kwd, const char *sptr, bool persistent,
|
||||
static order *create_order_i(order *ord, keyword_t kwd, const char *sptr, bool persistent,
|
||||
bool noerror, const struct locale *lang)
|
||||
{
|
||||
order *ord = NULL;
|
||||
int lindex;
|
||||
|
||||
assert(ord);
|
||||
if (kwd == NOKEYWORD || keyword_disabled(kwd)) {
|
||||
log_error("trying to create an order for disabled keyword %s.", keyword(kwd));
|
||||
return NULL;
|
||||
|
@ -316,11 +311,12 @@ static order *create_order_i(keyword_t kwd, const char *sptr, bool persistent,
|
|||
}
|
||||
locale_array[lindex]->lang = lang;
|
||||
|
||||
ord = (order *)malloc(sizeof(order));
|
||||
ord->_persistent = persistent;
|
||||
ord->_noerror = noerror;
|
||||
ord->command = (int)kwd;
|
||||
if (persistent) ord->command |= CMD_PERSIST;
|
||||
if (noerror) ord->command |= CMD_QUIET;
|
||||
ord->next = NULL;
|
||||
|
||||
while (isspace(*(unsigned char *)sptr)) ++sptr;
|
||||
ord->data = create_data(kwd, sptr, lindex);
|
||||
|
||||
return ord;
|
||||
|
@ -329,6 +325,7 @@ static order *create_order_i(keyword_t kwd, const char *sptr, bool persistent,
|
|||
order *create_order(keyword_t kwd, const struct locale * lang,
|
||||
const char *params, ...)
|
||||
{
|
||||
order *ord;
|
||||
char zBuffer[DISPLAYSIZE];
|
||||
if (params) {
|
||||
char *bufp = zBuffer;
|
||||
|
@ -379,42 +376,40 @@ order *create_order(keyword_t kwd, const struct locale * lang,
|
|||
else {
|
||||
zBuffer[0] = 0;
|
||||
}
|
||||
return create_order_i(kwd, zBuffer, false, false, lang);
|
||||
ord = (order *)malloc(sizeof(order));
|
||||
return create_order_i(ord, kwd, zBuffer, false, false, lang);
|
||||
}
|
||||
|
||||
order *parse_order(const char *s, const struct locale * lang)
|
||||
{
|
||||
assert(lang);
|
||||
assert(s);
|
||||
while (*s && !isalnum(*(unsigned char *)s) && !ispunct(*(unsigned char *)s)) {
|
||||
++s;
|
||||
}
|
||||
if (*s != 0) {
|
||||
keyword_t kwd;
|
||||
const char *sptr;
|
||||
keyword_t kwd = NOKEYWORD;
|
||||
const char *sptr = s;
|
||||
bool persistent = false, noerror = false;
|
||||
const char * p;
|
||||
|
||||
while (*s == '!' || *s=='@') {
|
||||
if (*s=='!') noerror = true;
|
||||
else if (*s == '@') persistent = true;
|
||||
++s;
|
||||
}
|
||||
sptr = s;
|
||||
p = *sptr ? parse_token_depr(&sptr) : 0;
|
||||
kwd = p ? get_keyword(p, lang) : NOKEYWORD;
|
||||
if (p) {
|
||||
while (*p == '!' || *p == '@') {
|
||||
if (*p == '!') noerror = true;
|
||||
else if (*p == '@') persistent = true;
|
||||
++p;
|
||||
}
|
||||
kwd = get_keyword(p, lang);
|
||||
}
|
||||
if (kwd == K_MAKE) {
|
||||
const char *s, *sp = sptr;
|
||||
s = parse_token_depr(&sp);
|
||||
if (s && isparam(s, lang, P_TEMP)) {
|
||||
const char *sp = sptr;
|
||||
p = parse_token_depr(&sp);
|
||||
if (p && isparam(p, lang, P_TEMP)) {
|
||||
kwd = K_MAKETEMP;
|
||||
sptr = sp;
|
||||
}
|
||||
}
|
||||
if (kwd != NOKEYWORD) {
|
||||
while (isspace(*(unsigned char *)sptr)) ++sptr;
|
||||
s = sptr;
|
||||
return create_order_i(kwd, s, persistent, noerror, lang);
|
||||
order *ord = (order *)malloc(sizeof(order));
|
||||
return create_order_i(ord, kwd, sptr, persistent, noerror, lang);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
|
@ -561,10 +556,15 @@ bool is_persistent(const order * ord)
|
|||
case K_KOMMENTAR:
|
||||
return true;
|
||||
default:
|
||||
return ord->_persistent || is_repeated(kwd);
|
||||
return (ord->command & CMD_PERSIST) || is_repeated(kwd);
|
||||
}
|
||||
}
|
||||
|
||||
bool is_silent(const order * ord)
|
||||
{
|
||||
return (ord->command & CMD_QUIET) != 0;
|
||||
}
|
||||
|
||||
char *write_order(const order * ord, char *buffer, size_t size)
|
||||
{
|
||||
if (ord == 0) {
|
||||
|
@ -595,5 +595,5 @@ keyword_t init_order(const struct order *ord)
|
|||
{
|
||||
assert(ord && ord->data);
|
||||
init_tokens_str(ord->data->_str);
|
||||
return ord->data->_keyword;
|
||||
return ORD_KEYWORD(ord);
|
||||
}
|
||||
|
|
|
@ -32,32 +32,36 @@ extern "C" {
|
|||
|
||||
struct order_data;
|
||||
|
||||
#define CMD_QUIET 0x010000
|
||||
#define CMD_PERSIST 0x020000
|
||||
#define CMD_DEFAULT 0x040000
|
||||
|
||||
typedef struct order {
|
||||
struct order *next;
|
||||
/* do not access this data: */
|
||||
struct order_data *data;
|
||||
bool _persistent;
|
||||
bool _noerror;
|
||||
int command;
|
||||
} order;
|
||||
|
||||
/* constructor */
|
||||
extern order *create_order(keyword_t kwd, const struct locale *lang,
|
||||
order *create_order(keyword_t kwd, const struct locale *lang,
|
||||
const char *params, ...);
|
||||
extern order *parse_order(const char *s, const struct locale *lang);
|
||||
extern void replace_order(order ** dst, order * orig, const order * src);
|
||||
order *parse_order(const char *s, const struct locale *lang);
|
||||
void replace_order(order ** dst, order * orig, const order * src);
|
||||
|
||||
/* reference counted copies of orders: */
|
||||
extern order *copy_order(const order * ord);
|
||||
extern void free_order(order * ord);
|
||||
extern void free_orders(order ** olist);
|
||||
order *copy_order(const order * ord);
|
||||
void free_order(order * ord);
|
||||
void free_orders(order ** olist);
|
||||
|
||||
extern void push_order(struct order **olist, struct order *ord);
|
||||
void push_order(struct order **olist, struct order *ord);
|
||||
|
||||
/* access functions for orders */
|
||||
keyword_t getkeyword(const order * ord);
|
||||
void set_order(order ** destp, order * src);
|
||||
char* get_command(const order *ord, char *buffer, size_t size);
|
||||
bool is_persistent(const order * ord);
|
||||
bool is_silent(const order * ord);
|
||||
bool is_exclusive(const order * ord);
|
||||
bool is_repeated(keyword_t kwd);
|
||||
bool is_long(keyword_t kwd);
|
||||
|
|
|
@ -38,8 +38,7 @@ static void test_parse_order(CuTest *tc) {
|
|||
|
||||
ord = parse_order("MOVE NORTH", lang);
|
||||
CuAssertPtrNotNull(tc, ord);
|
||||
CuAssertTrue(tc, !ord->_noerror);
|
||||
CuAssertTrue(tc, !ord->_persistent);
|
||||
CuAssertIntEquals(tc, K_MOVE, ord->command);
|
||||
CuAssertIntEquals(tc, K_MOVE, getkeyword(ord));
|
||||
CuAssertStrEquals(tc, "move NORTH", get_command(ord, cmd, sizeof(cmd)));
|
||||
|
||||
|
@ -49,26 +48,37 @@ static void test_parse_order(CuTest *tc) {
|
|||
|
||||
ord = parse_order("!MOVE NORTH", lang);
|
||||
CuAssertPtrNotNull(tc, ord);
|
||||
CuAssertTrue(tc, ord->_noerror);
|
||||
CuAssertTrue(tc, !ord->_persistent);
|
||||
CuAssertPtrNotNull(tc, ord->data);
|
||||
CuAssertIntEquals(tc, K_MOVE, getkeyword(ord));
|
||||
CuAssertIntEquals(tc, K_MOVE | CMD_QUIET, ord->command);
|
||||
free_order(ord);
|
||||
|
||||
ord = parse_order("@MOVE NORTH", lang);
|
||||
CuAssertPtrNotNull(tc, ord);
|
||||
CuAssertTrue(tc, !ord->_noerror);
|
||||
CuAssertTrue(tc, ord->_persistent);
|
||||
free_order(ord);
|
||||
|
||||
ord = parse_order("@!MOVE NORTH", lang);
|
||||
CuAssertPtrNotNull(tc, ord);
|
||||
CuAssertTrue(tc, ord->_noerror);
|
||||
CuAssertTrue(tc, ord->_persistent);
|
||||
CuAssertPtrNotNull(tc, ord->data);
|
||||
CuAssertIntEquals(tc, K_MOVE, getkeyword(ord));
|
||||
CuAssertIntEquals(tc, K_MOVE | CMD_PERSIST, ord->command);
|
||||
free_order(ord);
|
||||
|
||||
ord = parse_order("!@MOVE NORTH", lang);
|
||||
CuAssertPtrNotNull(tc, ord);
|
||||
CuAssertTrue(tc, ord->_noerror);
|
||||
CuAssertTrue(tc, ord->_persistent);
|
||||
CuAssertPtrNotNull(tc, ord->data);
|
||||
CuAssertIntEquals(tc, K_MOVE, getkeyword(ord));
|
||||
CuAssertIntEquals(tc, K_MOVE | CMD_PERSIST | CMD_QUIET, ord->command);
|
||||
free_order(ord);
|
||||
|
||||
ord = parse_order("@!MOVE NORTH", lang);
|
||||
CuAssertPtrNotNull(tc, ord);
|
||||
CuAssertPtrNotNull(tc, ord->data);
|
||||
CuAssertIntEquals(tc, K_MOVE, getkeyword(ord));
|
||||
CuAssertIntEquals(tc, K_MOVE | CMD_PERSIST | CMD_QUIET, ord->command);
|
||||
free_order(ord);
|
||||
|
||||
ord = parse_order(" !@MOVE NORTH", lang);
|
||||
CuAssertPtrNotNull(tc, ord);
|
||||
CuAssertPtrNotNull(tc, ord->data);
|
||||
CuAssertIntEquals(tc, K_MOVE, getkeyword(ord));
|
||||
CuAssertIntEquals(tc, K_MOVE | CMD_PERSIST | CMD_QUIET, ord->command);
|
||||
free_order(ord);
|
||||
|
||||
test_cleanup();
|
||||
|
@ -204,16 +214,84 @@ static void test_get_command(CuTest *tc) {
|
|||
lang = test_create_locale();
|
||||
ord = create_order(K_MAKE, lang, "iron");
|
||||
CuAssertStrEquals(tc, "make iron", get_command(ord, buf, sizeof(buf)));
|
||||
ord->_noerror = true;
|
||||
ord->command |= CMD_QUIET;
|
||||
CuAssertStrEquals(tc, "!make iron", get_command(ord, buf, sizeof(buf)));
|
||||
ord->_persistent = true;
|
||||
ord->command |= CMD_PERSIST;
|
||||
CuAssertStrEquals(tc, "!@make iron", get_command(ord, buf, sizeof(buf)));
|
||||
ord->_noerror = false;
|
||||
ord->command = K_MAKE | CMD_PERSIST;
|
||||
CuAssertStrEquals(tc, "@make iron", get_command(ord, buf, sizeof(buf)));
|
||||
free_order(ord);
|
||||
test_cleanup();
|
||||
}
|
||||
|
||||
static void test_is_persistent(CuTest *tc) {
|
||||
order *ord;
|
||||
struct locale *lang;
|
||||
|
||||
test_setup();
|
||||
lang = test_create_locale();
|
||||
|
||||
ord = parse_order("@invalid", lang);
|
||||
CuAssertPtrEquals(tc, NULL, ord);
|
||||
|
||||
ord = parse_order("give", lang);
|
||||
CuAssertIntEquals(tc, K_GIVE, ord->command);
|
||||
CuAssertTrue(tc, !is_persistent(ord));
|
||||
free_order(ord);
|
||||
|
||||
ord = parse_order("@give", lang);
|
||||
CuAssertTrue(tc, !is_repeated(K_GIVE));
|
||||
CuAssertIntEquals(tc, K_GIVE | CMD_PERSIST, ord->command);
|
||||
CuAssertTrue(tc, is_persistent(ord));
|
||||
free_order(ord);
|
||||
|
||||
ord = parse_order("make", lang);
|
||||
CuAssertTrue(tc, is_repeated(K_MAKE));
|
||||
CuAssertIntEquals(tc, K_MAKE , ord->command);
|
||||
CuAssertTrue(tc, is_persistent(ord));
|
||||
free_order(ord);
|
||||
|
||||
ord = parse_order("@move", lang);
|
||||
CuAssertIntEquals(tc, K_MOVE | CMD_PERSIST, ord->command);
|
||||
CuAssertTrue(tc, !is_persistent(ord));
|
||||
free_order(ord);
|
||||
|
||||
ord = parse_order("// comment", lang);
|
||||
CuAssertTrue(tc, is_persistent(ord));
|
||||
CuAssertIntEquals(tc, K_KOMMENTAR, ord->command);
|
||||
free_order(ord);
|
||||
|
||||
test_cleanup();
|
||||
}
|
||||
|
||||
|
||||
static void test_is_silent(CuTest *tc) {
|
||||
order *ord;
|
||||
struct locale *lang;
|
||||
|
||||
test_setup();
|
||||
lang = test_create_locale();
|
||||
|
||||
ord = parse_order("make", lang);
|
||||
CuAssertIntEquals(tc, K_MAKE, ord->command);
|
||||
CuAssertTrue(tc, !is_silent(ord));
|
||||
free_order(ord);
|
||||
|
||||
ord = parse_order("!make", lang);
|
||||
CuAssertIntEquals(tc, K_MAKE | CMD_QUIET, ord->command);
|
||||
CuAssertTrue(tc, is_silent(ord));
|
||||
free_order(ord);
|
||||
|
||||
ord = parse_order("@invalid", lang);
|
||||
CuAssertPtrEquals(tc, NULL, ord);
|
||||
|
||||
ord = parse_order("// comment", lang);
|
||||
CuAssertTrue(tc, is_persistent(ord));
|
||||
CuAssertIntEquals(tc, K_KOMMENTAR, ord->command);
|
||||
free_order(ord);
|
||||
|
||||
test_cleanup();
|
||||
}
|
||||
CuSuite *get_order_suite(void)
|
||||
{
|
||||
CuSuite *suite = CuSuiteNew();
|
||||
|
@ -227,5 +305,7 @@ CuSuite *get_order_suite(void)
|
|||
SUITE_ADD_TEST(suite, test_skip_token);
|
||||
SUITE_ADD_TEST(suite, test_getstrtoken);
|
||||
SUITE_ADD_TEST(suite, test_get_command);
|
||||
SUITE_ADD_TEST(suite, test_is_persistent);
|
||||
SUITE_ADD_TEST(suite, test_is_silent);
|
||||
return suite;
|
||||
}
|
||||
|
|
|
@ -258,39 +258,6 @@ unsigned char index)
|
|||
return (rel + ursprung_y(f, pl, NULL) + plane_center_y(pl));
|
||||
}
|
||||
|
||||
static int resolve_plane(variant id, void *addr)
|
||||
{
|
||||
int result = 0;
|
||||
plane *pl = NULL;
|
||||
if (id.i != 0) {
|
||||
pl = getplanebyid(id.i);
|
||||
if (pl == NULL) {
|
||||
result = -1;
|
||||
}
|
||||
}
|
||||
*(plane **)addr = pl;
|
||||
return result;
|
||||
}
|
||||
|
||||
void write_plane_reference(const plane * u, struct storage *store)
|
||||
{
|
||||
WRITE_INT(store, u ? (u->id) : 0);
|
||||
}
|
||||
|
||||
int read_plane_reference(plane ** pp, struct storage *store)
|
||||
{
|
||||
variant id;
|
||||
READ_INT(store, &id.i);
|
||||
if (id.i == 0) {
|
||||
*pp = NULL;
|
||||
return AT_READ_FAIL;
|
||||
}
|
||||
*pp = getplanebyid(id.i);
|
||||
if (*pp == NULL)
|
||||
ur_add(id, pp, resolve_plane);
|
||||
return AT_READ_OK;
|
||||
}
|
||||
|
||||
void free_plane(plane *pl) {
|
||||
free(pl->name);
|
||||
free(pl);
|
||||
|
|
|
@ -69,8 +69,6 @@ extern "C" {
|
|||
struct plane *get_homeplane(void);
|
||||
int rel_to_abs(const struct plane *pl, const struct faction *f,
|
||||
int rel, unsigned char index);
|
||||
void write_plane_reference(const plane * p, struct storage *store);
|
||||
int read_plane_reference(plane ** pp, struct storage *store);
|
||||
int plane_width(const plane * pl);
|
||||
int plane_height(const plane * pl);
|
||||
void adjust_coordinates(const struct faction *f, int *x, int *y, const struct plane *pl);
|
||||
|
|
|
@ -561,21 +561,15 @@ void write_race_reference(const race * rc, struct storage *store)
|
|||
WRITE_TOK(store, rc ? rc->_name : "none");
|
||||
}
|
||||
|
||||
variant read_race_reference(struct storage *store)
|
||||
struct race * read_race_reference(struct storage *store)
|
||||
{
|
||||
variant result;
|
||||
char zName[20];
|
||||
READ_TOK(store, zName, sizeof(zName));
|
||||
|
||||
if (strcmp(zName, "none") == 0) {
|
||||
result.v = NULL;
|
||||
return result;
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
result.v = rc_find_i(zName);
|
||||
}
|
||||
assert(result.v != NULL);
|
||||
return result;
|
||||
return rc_find_i(zName);
|
||||
}
|
||||
|
||||
void register_race_function(race_func func, const char *name) {
|
||||
|
|
|
@ -263,7 +263,7 @@ extern "C" {
|
|||
|
||||
void write_race_reference(const struct race *rc,
|
||||
struct storage *store);
|
||||
variant read_race_reference(struct storage *store);
|
||||
struct race *read_race_reference(struct storage *store);
|
||||
|
||||
const char *raceprefix(const struct unit *u);
|
||||
void register_race_function(race_func, const char *);
|
||||
|
|
|
@ -745,11 +745,17 @@ int rtrees(const region * r, int ageclass)
|
|||
|
||||
int rsettrees(const region * r, int ageclass, int value)
|
||||
{
|
||||
if (!r->land)
|
||||
if (!r->land) {
|
||||
assert(value == 0);
|
||||
}
|
||||
else {
|
||||
assert(value >= 0);
|
||||
return r->land->trees[ageclass] = value;
|
||||
if (value <= MAXTREES) {
|
||||
return r->land->trees[ageclass] = value;
|
||||
}
|
||||
else {
|
||||
r->land->trees[ageclass] = MAXTREES;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -819,8 +825,8 @@ void free_land(land_region * lr)
|
|||
lr->demands = d->next;
|
||||
free(d);
|
||||
}
|
||||
if (lr->name)
|
||||
free(lr->name);
|
||||
free(lr->name);
|
||||
free(lr->display);
|
||||
free(lr);
|
||||
}
|
||||
|
||||
|
@ -888,7 +894,6 @@ void free_region(region * r)
|
|||
{
|
||||
if (last == r)
|
||||
last = NULL;
|
||||
free(r->display);
|
||||
if (r->land)
|
||||
free_land(r->land);
|
||||
|
||||
|
@ -1082,7 +1087,6 @@ void terraform_region(region * r, const terrain_type * terrain)
|
|||
terraform_resources(r);
|
||||
|
||||
if (!fval(terrain, LAND_REGION)) {
|
||||
region_setinfo(r, NULL);
|
||||
if (r->land) {
|
||||
free_land(r->land);
|
||||
r->land = NULL;
|
||||
|
@ -1251,46 +1255,22 @@ int production(const region * r)
|
|||
return p;
|
||||
}
|
||||
|
||||
int resolve_region_coor(variant id, void *address)
|
||||
void resolve_region(region *r)
|
||||
{
|
||||
region *r = findregion(id.sa[0], id.sa[1]);
|
||||
if (r) {
|
||||
*(region **)address = r;
|
||||
return 0;
|
||||
}
|
||||
*(region **)address = NULL;
|
||||
return -1;
|
||||
resolve(RESOLVE_REGION | r->uid, r);
|
||||
}
|
||||
|
||||
int resolve_region_id(variant id, void *address)
|
||||
{
|
||||
region *r = NULL;
|
||||
if (id.i != 0) {
|
||||
r = findregionbyid(id.i);
|
||||
if (r == NULL) {
|
||||
*(region **)address = NULL;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
*(region **)address = r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
variant read_region_reference(gamedata *data)
|
||||
int read_region_reference(gamedata * data, region **rp, resolve_fun fun)
|
||||
{
|
||||
struct storage * store = data->store;
|
||||
variant result;
|
||||
if (data->version < UIDHASH_VERSION) {
|
||||
int n;
|
||||
READ_INT(store, &n);
|
||||
result.sa[0] = (short)n;
|
||||
READ_INT(store, &n);
|
||||
result.sa[1] = (short)n;
|
||||
int id = 0;
|
||||
|
||||
READ_INT(store, &id);
|
||||
*rp = findregionbyid(id);
|
||||
if (*rp == NULL) {
|
||||
ur_add(RESOLVE_REGION | id, (void **)rp, fun);
|
||||
}
|
||||
else {
|
||||
READ_INT(store, &result.i);
|
||||
}
|
||||
return result;
|
||||
return id;
|
||||
}
|
||||
|
||||
void write_region_reference(const region * r, struct storage *store)
|
||||
|
@ -1438,13 +1418,14 @@ faction *update_owners(region * r)
|
|||
|
||||
void region_setinfo(struct region *r, const char *info)
|
||||
{
|
||||
free(r->display);
|
||||
r->display = info ? strdup(info) : 0;
|
||||
assert(r->land);
|
||||
free(r->land->display);
|
||||
r->land->display = (info && info[0]) ? strdup(info) : 0;
|
||||
}
|
||||
|
||||
const char *region_getinfo(const region * r)
|
||||
{
|
||||
return r->display ? r->display : "";
|
||||
return (r->land && r->land->display) ? r->land->display : "";
|
||||
}
|
||||
|
||||
void region_setname(struct region *r, const char *name)
|
||||
|
|
|
@ -19,13 +19,17 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
#ifndef H_KRNL_REGION
|
||||
#define H_KRNL_REGION
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <util/resolve.h>
|
||||
|
||||
#include "types.h"
|
||||
#include "direction.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define MAXLUXURIES 16 /* there must be no more than MAXLUXURIES kinds of luxury goods in any game */
|
||||
#define MAXREGIONS 524287 /* must be prime for hashing. 262139 was a little small */
|
||||
#define MAXTREES 100 * 1000 * 1000 /* bug 2360: some players are crazy */
|
||||
|
||||
/* FAST_CONNECT: regions are directly connected to neighbours, saves doing
|
||||
a hash-access each time a neighbour is needed, 6 extra pointers per hex */
|
||||
|
@ -95,7 +99,7 @@ extern "C" {
|
|||
|
||||
typedef struct land_region {
|
||||
char *name;
|
||||
/* TODO: demand kann nach Konvertierung entfernt werden. */
|
||||
char *display;
|
||||
demand *demands;
|
||||
const struct item_type *herbtype;
|
||||
short herbs;
|
||||
|
@ -121,7 +125,6 @@ extern "C" {
|
|||
int uid; /* a unique id */
|
||||
int x, y;
|
||||
struct plane *_plane; /* to access, use rplane(r) */
|
||||
char *display;
|
||||
int flags;
|
||||
unsigned short age;
|
||||
struct message_list *msgs;
|
||||
|
@ -256,11 +259,10 @@ extern "C" {
|
|||
int region_get_morale(const region * r);
|
||||
void region_set_morale(region * r, int morale, int turn);
|
||||
|
||||
#define RESOLVE_REGION (TYP_REGION << 24)
|
||||
void resolve_region(region *r);
|
||||
void write_region_reference(const struct region *r, struct storage *store);
|
||||
variant read_region_reference(struct gamedata *data);
|
||||
int resolve_region_coor(variant id, void *address);
|
||||
int resolve_region_id(variant id, void *address);
|
||||
#define RESOLVE_REGION(version) ((version<UIDHASH_VERSION)?resolve_region_coor:resolve_region_id)
|
||||
int read_region_reference(struct gamedata *data, region **rp, resolve_fun fun);
|
||||
|
||||
const char *regionname(const struct region *r, const struct faction *f);
|
||||
|
||||
|
|
|
@ -78,10 +78,29 @@ static void test_region_getset_resource(CuTest *tc) {
|
|||
test_cleanup();
|
||||
}
|
||||
|
||||
static void test_trees(CuTest *tc) {
|
||||
region *r;
|
||||
|
||||
test_setup();
|
||||
r = test_create_region(0, 0, NULL);
|
||||
rsettrees(r, 0, 1000);
|
||||
rsettrees(r, 1, 2000);
|
||||
rsettrees(r, 2, 3000);
|
||||
CuAssertIntEquals(tc, 1000, rtrees(r, 0));
|
||||
CuAssertIntEquals(tc, 2000, rtrees(r, 1));
|
||||
CuAssertIntEquals(tc, 3000, rtrees(r, 2));
|
||||
rsettrees(r, 0, MAXTREES);
|
||||
CuAssertIntEquals(tc, MAXTREES, rtrees(r, 0));
|
||||
rsettrees(r, 0, MAXTREES+100);
|
||||
CuAssertIntEquals(tc, MAXTREES, rtrees(r, 0));
|
||||
test_cleanup();
|
||||
}
|
||||
|
||||
CuSuite *get_region_suite(void)
|
||||
{
|
||||
CuSuite *suite = CuSuiteNew();
|
||||
SUITE_ADD_TEST(suite, test_terraform);
|
||||
SUITE_ADD_TEST(suite, test_trees);
|
||||
SUITE_ADD_TEST(suite, test_region_getset_resource);
|
||||
SUITE_ADD_TEST(suite, test_region_get_owner);
|
||||
return suite;
|
||||
|
|
|
@ -24,11 +24,13 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
#include "alchemy.h"
|
||||
#include "alliance.h"
|
||||
#include "ally.h"
|
||||
#include "connection.h"
|
||||
#include "building.h"
|
||||
#include "connection.h"
|
||||
#include "equipment.h"
|
||||
#include "faction.h"
|
||||
#include "group.h"
|
||||
#include "item.h"
|
||||
#include "magic.h"
|
||||
#include "messages.h"
|
||||
#include "move.h"
|
||||
#include "objtypes.h"
|
||||
|
@ -51,6 +53,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
#include <attributes/attributes.h>
|
||||
#include <attributes/key.h>
|
||||
#include <triggers/timeout.h>
|
||||
#include <triggers/shock.h>
|
||||
|
||||
/* util includes */
|
||||
#include <util/assert.h>
|
||||
|
@ -120,217 +123,6 @@ char *rns(FILE * f, char *c, size_t size)
|
|||
return c;
|
||||
}
|
||||
|
||||
|
||||
static unit *unitorders(FILE * F, int enc, struct faction *f)
|
||||
{
|
||||
int i;
|
||||
unit *u;
|
||||
|
||||
if (!f)
|
||||
return NULL;
|
||||
|
||||
i = getid();
|
||||
u = findunitg(i, NULL);
|
||||
|
||||
if (u && u->faction == f) {
|
||||
order **ordp;
|
||||
|
||||
if (!fval(u, UFL_ORDERS)) {
|
||||
/* alle wiederholbaren, langen befehle werden gesichert: */
|
||||
fset(u, UFL_ORDERS);
|
||||
u->old_orders = u->orders;
|
||||
ordp = &u->old_orders;
|
||||
while (*ordp) {
|
||||
order *ord = *ordp;
|
||||
keyword_t kwd = getkeyword(ord);
|
||||
if (!is_repeated(kwd)) {
|
||||
*ordp = ord->next;
|
||||
ord->next = NULL;
|
||||
free_order(ord);
|
||||
}
|
||||
else {
|
||||
ordp = &ord->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
free_orders(&u->orders);
|
||||
}
|
||||
u->orders = 0;
|
||||
|
||||
ordp = &u->orders;
|
||||
|
||||
for (;;) {
|
||||
const char *s;
|
||||
/* Erst wenn wir sicher sind, dass kein Befehl
|
||||
* eingegeben wurde, checken wir, ob nun eine neue
|
||||
* Einheit oder ein neuer Spieler drankommt */
|
||||
|
||||
s = getbuf(F, enc);
|
||||
if (s == NULL)
|
||||
break;
|
||||
|
||||
if (s[0]) {
|
||||
if (s[0] != '@') {
|
||||
char token[64];
|
||||
const char *stok = s;
|
||||
stok = parse_token(&stok, token, sizeof(token));
|
||||
|
||||
if (stok) {
|
||||
bool quit = false;
|
||||
param_t param = findparam(stok, u->faction->locale);
|
||||
switch (param) {
|
||||
case P_UNIT:
|
||||
case P_REGION:
|
||||
quit = true;
|
||||
break;
|
||||
case P_FACTION:
|
||||
case P_NEXT:
|
||||
case P_GAMENAME:
|
||||
/* these terminate the orders, so we apply extra checking */
|
||||
if (strlen(stok) >= 3) {
|
||||
quit = true;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
quit = false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (quit) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Nun wird der Befehl erzeut und eingehängt */
|
||||
*ordp = parse_order(s, u->faction->locale);
|
||||
if (*ordp) {
|
||||
ordp = &(*ordp)->next;
|
||||
}
|
||||
else {
|
||||
ADDMSG(&f->msgs, msg_message("parse_error", "unit command", u, s));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
return u;
|
||||
}
|
||||
|
||||
static faction *factionorders(void)
|
||||
{
|
||||
faction *f = NULL;
|
||||
int fid = getid();
|
||||
|
||||
f = findfaction(fid);
|
||||
|
||||
if (f != NULL && !fval(f, FFL_NPC)) {
|
||||
char token[128];
|
||||
const char *pass = gettoken(token, sizeof(token));
|
||||
|
||||
if (!checkpasswd(f, (const char *)pass)) {
|
||||
log_debug("Invalid password for faction %s", itoa36(fid));
|
||||
ADDMSG(&f->msgs, msg_message("wrongpasswd", "password", pass));
|
||||
return 0;
|
||||
}
|
||||
/* Die Partei hat sich zumindest gemeldet, so dass sie noch
|
||||
* nicht als untätig gilt */
|
||||
f->lastorders = turn;
|
||||
|
||||
}
|
||||
else {
|
||||
log_debug("orders for invalid faction %s", itoa36(fid));
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
int readorders(const char *filename)
|
||||
{
|
||||
FILE *F = NULL;
|
||||
const char *b;
|
||||
int nfactions = 0;
|
||||
struct faction *f = NULL;
|
||||
|
||||
F = fopen(filename, "r");
|
||||
if (!F) {
|
||||
perror(filename);
|
||||
return -1;
|
||||
}
|
||||
log_info("reading orders from %s", filename);
|
||||
|
||||
/* TODO: recognize UTF8 BOM */
|
||||
b = getbuf(F, enc_gamedata);
|
||||
|
||||
/* Auffinden der ersten Partei, und danach abarbeiten bis zur letzten
|
||||
* Partei */
|
||||
|
||||
while (b) {
|
||||
char token[128];
|
||||
const struct locale *lang = f ? f->locale : default_locale;
|
||||
param_t p;
|
||||
const char *s;
|
||||
init_tokens_str(b);
|
||||
s = gettoken(token, sizeof(token));
|
||||
p = findparam_block(s, lang, true);
|
||||
switch (p) {
|
||||
case P_GAMENAME:
|
||||
case P_FACTION:
|
||||
f = factionorders();
|
||||
if (f) {
|
||||
++nfactions;
|
||||
}
|
||||
|
||||
b = getbuf(F, enc_gamedata);
|
||||
break;
|
||||
|
||||
/* in factionorders wird nur eine zeile gelesen:
|
||||
* diejenige mit dem passwort. Die befehle der units
|
||||
* werden geloescht, und die Partei wird als aktiv
|
||||
* vermerkt. */
|
||||
|
||||
case P_UNIT:
|
||||
if (!f || !unitorders(F, enc_gamedata, f)) {
|
||||
do {
|
||||
b = getbuf(F, enc_gamedata);
|
||||
if (!b) {
|
||||
break;
|
||||
}
|
||||
init_tokens_str(b);
|
||||
s = gettoken(token, sizeof(token));
|
||||
p = (s && s[0] != '@') ? findparam(s, lang) : NOPARAM;
|
||||
} while ((p != P_UNIT || !f) && p != P_FACTION && p != P_NEXT
|
||||
&& p != P_GAMENAME);
|
||||
}
|
||||
break;
|
||||
|
||||
/* Falls in unitorders() abgebrochen wird, steht dort entweder eine neue
|
||||
* Partei, eine neue Einheit oder das File-Ende. Das switch() wird erneut
|
||||
* durchlaufen, und die entsprechende Funktion aufgerufen. Man darf buf
|
||||
* auf alle Fälle nicht überschreiben! Bei allen anderen Einträgen hier
|
||||
* muss buf erneut gefüllt werden, da die betreffende Information in nur
|
||||
* einer Zeile steht, und nun die nächste gelesen werden muss. */
|
||||
|
||||
case P_NEXT:
|
||||
f = NULL;
|
||||
b = getbuf(F, enc_gamedata);
|
||||
break;
|
||||
|
||||
default:
|
||||
b = getbuf(F, enc_gamedata);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(F);
|
||||
log_info("done reading orders for %d factions", nfactions);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
|
||||
/* #define INNER_WORLD */
|
||||
|
@ -375,7 +167,7 @@ race_t typus2race(unsigned char typus)
|
|||
return NORACE;
|
||||
}
|
||||
|
||||
static void read_alliances(struct gamedata *data)
|
||||
static void read_alliances(gamedata *data)
|
||||
{
|
||||
storage *store = data->store;
|
||||
char pbuf[8];
|
||||
|
@ -397,8 +189,7 @@ static void read_alliances(struct gamedata *data)
|
|||
READ_INT(store, &al->flags);
|
||||
}
|
||||
if (data->version >= ALLIANCELEADER_VERSION) {
|
||||
read_reference(&al->_leader, data, read_faction_reference,
|
||||
resolve_faction);
|
||||
read_faction_reference(data, &al->_leader, NULL);
|
||||
READ_INT(store, &id);
|
||||
}
|
||||
else {
|
||||
|
@ -418,7 +209,6 @@ void read_planes(gamedata *data) {
|
|||
READ_INT(store, &nread);
|
||||
while (--nread >= 0) {
|
||||
int id;
|
||||
variant fno;
|
||||
plane *pl;
|
||||
|
||||
READ_INT(store, &id);
|
||||
|
@ -457,9 +247,10 @@ void read_planes(gamedata *data) {
|
|||
else {
|
||||
/* WATCHERS - eliminated in February 2016, ca. turn 966 */
|
||||
if (data->version < NOWATCH_VERSION) {
|
||||
fno = read_faction_reference(data);
|
||||
while (fno.i) {
|
||||
fno = read_faction_reference(data);
|
||||
int fno;
|
||||
READ_INT(data->store, &fno);
|
||||
while (fno) {
|
||||
READ_INT(data->store, &fno);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -490,7 +281,7 @@ void write_planes(storage *store) {
|
|||
}
|
||||
}
|
||||
|
||||
void write_alliances(struct gamedata *data)
|
||||
void write_alliances(gamedata *data)
|
||||
{
|
||||
alliance *al = alliances;
|
||||
while (al) {
|
||||
|
@ -507,22 +298,7 @@ void write_alliances(struct gamedata *data)
|
|||
WRITE_SECTION(data->store);
|
||||
}
|
||||
|
||||
static int resolve_owner(variant id, void *address)
|
||||
{
|
||||
region_owner *owner = (region_owner *)address;
|
||||
int result = 0;
|
||||
faction *f = NULL;
|
||||
if (id.i != 0) {
|
||||
f = findfaction(id.i);
|
||||
if (f == NULL) {
|
||||
log_error("region has an invalid owner (%s)", itoa36(id.i));
|
||||
}
|
||||
}
|
||||
owner->owner = f;
|
||||
return result;
|
||||
}
|
||||
|
||||
static void read_owner(struct gamedata *data, region_owner ** powner)
|
||||
static void read_owner(gamedata *data, region_owner ** powner)
|
||||
{
|
||||
int since_turn;
|
||||
|
||||
|
@ -538,9 +314,7 @@ static void read_owner(struct gamedata *data, region_owner ** powner)
|
|||
owner->flags = 0;
|
||||
}
|
||||
if (data->version >= OWNER_3_VERSION) {
|
||||
int id;
|
||||
READ_INT(data->store, &id);
|
||||
owner->last_owner = id ? findfaction(id) : NULL;
|
||||
read_faction_reference(data, &owner->last_owner, NULL);
|
||||
}
|
||||
else if (data->version >= OWNER_2_VERSION) {
|
||||
int id;
|
||||
|
@ -553,7 +327,7 @@ static void read_owner(struct gamedata *data, region_owner ** powner)
|
|||
else {
|
||||
owner->last_owner = NULL;
|
||||
}
|
||||
read_reference(owner, data, &read_faction_reference, &resolve_owner);
|
||||
read_faction_reference(data, &owner->owner, NULL);
|
||||
*powner = owner;
|
||||
}
|
||||
else {
|
||||
|
@ -561,7 +335,7 @@ static void read_owner(struct gamedata *data, region_owner ** powner)
|
|||
}
|
||||
}
|
||||
|
||||
static void write_owner(struct gamedata *data, region_owner * owner)
|
||||
static void write_owner(gamedata *data, region_owner * owner)
|
||||
{
|
||||
if (owner) {
|
||||
faction *f;
|
||||
|
@ -601,8 +375,7 @@ int current_turn(void)
|
|||
return cturn;
|
||||
}
|
||||
|
||||
static void
|
||||
writeorder(struct gamedata *data, const struct order *ord,
|
||||
static void writeorder(gamedata *data, const struct order *ord,
|
||||
const struct locale *lang)
|
||||
{
|
||||
char obuf[1024];
|
||||
|
@ -611,7 +384,58 @@ writeorder(struct gamedata *data, const struct order *ord,
|
|||
WRITE_STR(data->store, obuf);
|
||||
}
|
||||
|
||||
unit *read_unit(struct gamedata *data)
|
||||
static void read_skills(gamedata *data, unit *u)
|
||||
{
|
||||
if (data->version < SKILLSORT_VERSION) {
|
||||
for (;;) {
|
||||
int n = NOSKILL, level, weeks;
|
||||
skill_t sk;
|
||||
READ_INT(data->store, &n);
|
||||
sk = (skill_t)n;
|
||||
if (sk == NOSKILL) break;
|
||||
READ_INT(data->store, &level);
|
||||
READ_INT(data->store, &weeks);
|
||||
if (level) {
|
||||
skill *sv = add_skill(u, sk);
|
||||
sv->level = sv->old = (unsigned char)level;
|
||||
sv->weeks = (unsigned char)weeks;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
int i;
|
||||
READ_INT(data->store, &u->skill_size);
|
||||
u->skills = malloc(sizeof(skill)*u->skill_size);
|
||||
for (i = 0; i != u->skill_size; ++i) {
|
||||
skill *sv = u->skills + i;
|
||||
int val;
|
||||
READ_INT(data->store, &val);
|
||||
sv->id = (skill_t)val;
|
||||
READ_INT(data->store, &sv->level);
|
||||
sv->old = sv->level;
|
||||
READ_INT(data->store, &sv->weeks);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void write_skills(gamedata *data, const unit *u) {
|
||||
int i;
|
||||
skill_t sk = NOSKILL;
|
||||
WRITE_INT(data->store, u->skill_size);
|
||||
for (i = 0; i != u->skill_size; ++i) {
|
||||
skill *sv = u->skills + i;
|
||||
#ifndef NDEBUG
|
||||
assert(sv->id > sk);
|
||||
sk = sv->id;
|
||||
assert(sv->weeks <= sv->level * 2 + 1);
|
||||
#endif
|
||||
WRITE_INT(data->store, sv->id);
|
||||
WRITE_INT(data->store, sv->level);
|
||||
WRITE_INT(data->store, sv->weeks);
|
||||
}
|
||||
}
|
||||
|
||||
unit *read_unit(gamedata *data)
|
||||
{
|
||||
unit *u;
|
||||
const race *rc;
|
||||
|
@ -758,20 +582,7 @@ unit *read_unit(struct gamedata *data)
|
|||
set_order(&u->thisorder, NULL);
|
||||
|
||||
assert(u_race(u));
|
||||
for (;;) {
|
||||
int n = NOSKILL, level, weeks;
|
||||
skill_t sk;
|
||||
READ_INT(data->store, &n);
|
||||
sk = (skill_t)n;
|
||||
if (sk == NOSKILL) break;
|
||||
READ_INT(data->store, &level);
|
||||
READ_INT(data->store, &weeks);
|
||||
if (level) {
|
||||
skill *sv = add_skill(u, sk);
|
||||
sv->level = sv->old = (unsigned char)level;
|
||||
sv->weeks = (unsigned char)weeks;
|
||||
}
|
||||
}
|
||||
read_skills(data, u);
|
||||
read_items(data->store, &u->items);
|
||||
READ_INT(data->store, &u->hp);
|
||||
if (u->hp < u->number) {
|
||||
|
@ -779,13 +590,14 @@ unit *read_unit(struct gamedata *data)
|
|||
u->hp = u->number;
|
||||
}
|
||||
read_attribs(data, &u->attribs, u);
|
||||
resolve_unit(u);
|
||||
return u;
|
||||
}
|
||||
|
||||
void write_unit(struct gamedata *data, const unit * u)
|
||||
void write_unit(gamedata *data, const unit * u)
|
||||
{
|
||||
order *ord;
|
||||
int i, p = 0;
|
||||
int p = 0;
|
||||
unsigned int flags = u->flags & UFL_SAVEMASK;
|
||||
const race *irace = u_irace(u);
|
||||
|
||||
|
@ -833,18 +645,7 @@ void write_unit(struct gamedata *data, const unit * u)
|
|||
WRITE_SECTION(data->store);
|
||||
|
||||
assert(u_race(u));
|
||||
|
||||
for (i = 0; i != u->skill_size; ++i) {
|
||||
skill *sv = u->skills + i;
|
||||
assert(sv->weeks <= sv->level * 2 + 1);
|
||||
if (sv->level > 0) {
|
||||
WRITE_INT(data->store, sv->id);
|
||||
WRITE_INT(data->store, sv->level);
|
||||
WRITE_INT(data->store, sv->weeks);
|
||||
}
|
||||
}
|
||||
WRITE_INT(data->store, -1);
|
||||
WRITE_SECTION(data->store);
|
||||
write_skills(data, u);
|
||||
write_items(data->store, u->items);
|
||||
WRITE_SECTION(data->store);
|
||||
if (u->hp == 0 && data->version < NORCSPELL_VERSION) {
|
||||
|
@ -857,11 +658,24 @@ void write_unit(struct gamedata *data, const unit * u)
|
|||
WRITE_SECTION(data->store);
|
||||
}
|
||||
|
||||
static region *readregion(struct gamedata *data, int x, int y)
|
||||
static void read_regioninfo(gamedata *data, const region *r, char *info, size_t len) {
|
||||
if (lomem) {
|
||||
READ_STR(data->store, NULL, 0);
|
||||
}
|
||||
else {
|
||||
READ_STR(data->store, info, len);
|
||||
if (unicode_utf8_trim(info) != 0) {
|
||||
log_warning("trim region %d info to '%s'", r->uid, info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static region *readregion(gamedata *data, int x, int y)
|
||||
{
|
||||
region *r = findregion(x, y);
|
||||
const terrain_type *terrain;
|
||||
char name[NAMESIZE];
|
||||
char info[DISPLAYSIZE];
|
||||
int uid = 0;
|
||||
int n;
|
||||
|
||||
|
@ -887,16 +701,11 @@ static region *readregion(struct gamedata *data, int x, int y)
|
|||
}
|
||||
r->land = 0;
|
||||
}
|
||||
if (lomem) {
|
||||
READ_STR(data->store, NULL, 0);
|
||||
if (data->version < LANDDISPLAY_VERSION) {
|
||||
read_regioninfo(data, r, info, sizeof(info));
|
||||
}
|
||||
else {
|
||||
char info[DISPLAYSIZE];
|
||||
READ_STR(data->store, info, sizeof(info));
|
||||
if (unicode_utf8_trim(info)!=0) {
|
||||
log_warning("trim region %d info to '%s'", uid, info);
|
||||
};
|
||||
region_setinfo(r, info);
|
||||
info[0] = '\0';
|
||||
}
|
||||
|
||||
READ_STR(data->store, name, sizeof(name));
|
||||
|
@ -913,15 +722,19 @@ static region *readregion(struct gamedata *data, int x, int y)
|
|||
if (fval(r->terrain, LAND_REGION)) {
|
||||
r->land = calloc(1, sizeof(land_region));
|
||||
READ_STR(data->store, name, sizeof(name));
|
||||
if (unicode_utf8_trim(name)!=0) {
|
||||
log_warning("trim region %d name to '%s'", uid, name);
|
||||
};
|
||||
if (unicode_utf8_trim(name) != 0) {
|
||||
log_warning("trim region %d name to '%s'", uid, name);
|
||||
};
|
||||
r->land->name = strdup(name);
|
||||
}
|
||||
if (r->land) {
|
||||
int i;
|
||||
rawmaterial **pres = &r->resources;
|
||||
|
||||
if (data->version >= LANDDISPLAY_VERSION) {
|
||||
read_regioninfo(data, r, info, sizeof(info));
|
||||
}
|
||||
region_setinfo(r, info);
|
||||
READ_INT(data->store, &i);
|
||||
if (i < 0) {
|
||||
log_error("number of trees in %s is %d.", regionname(r, NULL), i);
|
||||
|
@ -999,7 +812,11 @@ static region *readregion(struct gamedata *data, int x, int y)
|
|||
READ_INT(data->store, &n);
|
||||
rsetmoney(r, n);
|
||||
}
|
||||
|
||||
else {
|
||||
if (info[0]) {
|
||||
log_error("%s %d has a description: %s", r->terrain->_name, r->uid, info);
|
||||
}
|
||||
}
|
||||
assert(r->terrain != NULL);
|
||||
|
||||
if (r->land) {
|
||||
|
@ -1038,27 +855,27 @@ region *read_region(gamedata *data)
|
|||
READ_INT(store, &x);
|
||||
READ_INT(store, &y);
|
||||
r = readregion(data, x, y);
|
||||
resolve_region(r);
|
||||
return r;
|
||||
}
|
||||
|
||||
void writeregion(struct gamedata *data, const region * r)
|
||||
void writeregion(gamedata *data, const region * r)
|
||||
{
|
||||
assert(r);
|
||||
assert(data);
|
||||
|
||||
WRITE_INT(data->store, r->uid);
|
||||
WRITE_STR(data->store, region_getinfo(r));
|
||||
WRITE_TOK(data->store, r->terrain->_name);
|
||||
WRITE_INT(data->store, r->flags & RF_SAVEMASK);
|
||||
WRITE_INT(data->store, r->age);
|
||||
WRITE_SECTION(data->store);
|
||||
if (fval(r->terrain, LAND_REGION)) {
|
||||
if (r->land) {
|
||||
const item_type *rht;
|
||||
struct demand *demand;
|
||||
rawmaterial *res = r->resources;
|
||||
|
||||
assert(r->land);
|
||||
WRITE_STR(data->store, (const char *)r->land->name);
|
||||
WRITE_STR(data->store, region_getinfo(r));
|
||||
assert(rtrees(r, 0) >= 0);
|
||||
assert(rtrees(r, 1) >= 0);
|
||||
assert(rtrees(r, 2) >= 0);
|
||||
|
@ -1094,11 +911,9 @@ void writeregion(struct gamedata *data, const region * r)
|
|||
}
|
||||
WRITE_TOK(data->store, "end");
|
||||
WRITE_SECTION(data->store);
|
||||
#if RELEASE_VERSION>=REGIONOWNER_VERSION
|
||||
WRITE_INT(data->store, region_get_morale(r));
|
||||
write_owner(data, r->land->ownership);
|
||||
WRITE_SECTION(data->store);
|
||||
#endif
|
||||
}
|
||||
write_attribs(data->store, r->attribs, r);
|
||||
WRITE_SECTION(data->store);
|
||||
|
@ -1112,33 +927,6 @@ void write_region(gamedata *data, const region *r)
|
|||
writeregion(data, r);
|
||||
}
|
||||
|
||||
static ally **addally(const faction * f, ally ** sfp, int aid, int state)
|
||||
{
|
||||
struct faction *af = findfaction(aid);
|
||||
ally *sf;
|
||||
|
||||
state &= ~HELP_OBSERVE;
|
||||
state &= ~HELP_TRAVEL;
|
||||
state &= HelpMask();
|
||||
|
||||
if (state == 0)
|
||||
return sfp;
|
||||
|
||||
while (*sfp) {
|
||||
sfp = &(*sfp)->next;
|
||||
}
|
||||
|
||||
sf = ally_add(sfp, af);
|
||||
if (!sf->faction) {
|
||||
variant id;
|
||||
id.i = aid;
|
||||
ur_add(id, &sf->faction, resolve_faction);
|
||||
}
|
||||
sf->status = state & HELP_ALL;
|
||||
|
||||
return &sf->next;
|
||||
}
|
||||
|
||||
int get_spell_level_faction(const spell * sp, void * cbdata)
|
||||
{
|
||||
static spellbook * common = 0;
|
||||
|
@ -1215,9 +1003,8 @@ void _test_write_password(gamedata *data, const faction *f) {
|
|||
write_password(data, f);
|
||||
}
|
||||
|
||||
faction *read_faction(struct gamedata * data)
|
||||
faction *read_faction(gamedata * data)
|
||||
{
|
||||
ally **sfp;
|
||||
int planes, n;
|
||||
faction *f;
|
||||
char name[DISPLAYSIZE];
|
||||
|
@ -1346,28 +1133,17 @@ faction *read_faction(struct gamedata * data)
|
|||
/* mistakes were made in the past*/
|
||||
f->options &= ~want(O_JSON);
|
||||
}
|
||||
sfp = &f->allies;
|
||||
for (;;) {
|
||||
int aid = 0;
|
||||
READ_INT(data->store, &aid);
|
||||
if (aid > 0) {
|
||||
int state;
|
||||
READ_INT(data->store, &state);
|
||||
sfp = addally(f, sfp, aid, state);
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
read_allies(data, f);
|
||||
read_groups(data, f);
|
||||
f->spellbook = 0;
|
||||
if (data->version >= REGIONOWNER_VERSION) {
|
||||
read_spellbook(FactionSpells() ? &f->spellbook : 0, data, get_spell_level_faction, (void *)f);
|
||||
}
|
||||
resolve_faction(f);
|
||||
return f;
|
||||
}
|
||||
|
||||
void write_faction(struct gamedata *data, const faction * f)
|
||||
void write_faction(gamedata *data, const faction * f)
|
||||
{
|
||||
ally *sf;
|
||||
ursprung *ur;
|
||||
|
@ -1448,7 +1224,7 @@ static int cb_sb_maxlevel(spellbook_entry *sbe, void *cbdata) {
|
|||
|
||||
int readgame(const char *filename)
|
||||
{
|
||||
int n;
|
||||
int n, stream_version;
|
||||
char path[MAX_PATH];
|
||||
gamedata gdata = { 0 };
|
||||
storage store;
|
||||
|
@ -1465,11 +1241,8 @@ int readgame(const char *filename)
|
|||
return -1;
|
||||
}
|
||||
sz = fread(&gdata.version, sizeof(int), 1, F);
|
||||
if (sz != sizeof(int) || gdata.version >= INTPAK_VERSION) {
|
||||
int stream_version;
|
||||
size_t sz = fread(&stream_version, sizeof(int), 1, F);
|
||||
assert((sz == 1 && stream_version == STREAM_VERSION) || !"unsupported data format");
|
||||
}
|
||||
sz = fread(&stream_version, sizeof(int), 1, F);
|
||||
assert((sz == 1 && stream_version == STREAM_VERSION) || !"unsupported data format");
|
||||
assert(gdata.version >= MIN_VERSION || !"unsupported data format");
|
||||
assert(gdata.version <= MAX_VERSION || !"unsupported data format");
|
||||
|
||||
|
@ -1538,7 +1311,8 @@ struct building *read_building(gamedata *data) {
|
|||
log_error("building too big: %s (%s size %d of %d), fixing.", buildingname(b), b->type->_name, b->size, b->type->maxsize);
|
||||
b->size = b->type->maxsize;
|
||||
}
|
||||
return b;
|
||||
resolve_building(b);
|
||||
return b;
|
||||
}
|
||||
|
||||
void write_ship(gamedata *data, const ship *sh)
|
||||
|
@ -1556,7 +1330,7 @@ void write_ship(gamedata *data, const ship *sh)
|
|||
write_attribs(store, sh->attribs, sh);
|
||||
}
|
||||
|
||||
ship *read_ship(struct gamedata *data)
|
||||
ship *read_ship(gamedata *data)
|
||||
{
|
||||
char name[DISPLAYSIZE];
|
||||
ship *sh;
|
||||
|
@ -1607,7 +1381,78 @@ ship *read_ship(struct gamedata *data)
|
|||
}
|
||||
|
||||
|
||||
int read_game(gamedata *data) {
|
||||
static void fix_familiars(void) {
|
||||
region *r;
|
||||
for (r = regions; r; r = r->next) {
|
||||
unit * u;
|
||||
for (u = r->units; u; u = u->next) {
|
||||
if (u->_race != u->faction->race && (u->_race->flags & RCF_FAMILIAR)) {
|
||||
/* unit is potentially a familiar */
|
||||
attrib * a = a_find(u->attribs, &at_mage);
|
||||
attrib * am = a_find(u->attribs, &at_familiarmage);
|
||||
if (am) {
|
||||
sc_mage *mage = a ? (sc_mage *)a->data.v : NULL;
|
||||
/* a familiar */
|
||||
if (!mage) {
|
||||
log_error("%s seems to be a familiar with no magic.",
|
||||
unitname(u));
|
||||
mage = create_mage(u, M_GRAY);
|
||||
}
|
||||
if (!mage->spellbook) {
|
||||
char eqname[32];
|
||||
equipment *eq;
|
||||
|
||||
snprintf(eqname, sizeof(eqname), "fam_%s", u->_race->_name);
|
||||
eq = get_equipment(eqname);
|
||||
if (eq && eq->spells) {
|
||||
log_error("%s seems to be a familiar with no spells.",
|
||||
unitname(u));
|
||||
/* magical familiar, no spells */
|
||||
equip_unit_mask(u, eq, EQUIP_SPELLS);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (a) {
|
||||
/* not a familiar, but magical */
|
||||
attrib * ae = a_find(u->attribs, &at_eventhandler);
|
||||
if (ae) {
|
||||
trigger **tlist;
|
||||
tlist = get_triggers(ae, "destroy");
|
||||
if (tlist) {
|
||||
trigger *t;
|
||||
unit *um = NULL;
|
||||
for (t = *tlist; t; t = t->next) {
|
||||
if (t->type == &tt_shock) {
|
||||
um = (unit *)t->data.v;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (um) {
|
||||
attrib *af = a_find(um->attribs, &at_familiar);
|
||||
log_error("%s seems to be a broken familiar of %s.",
|
||||
unitname(u), unitname(um));
|
||||
if (af) {
|
||||
unit * uf = (unit *)af->data.v;
|
||||
log_error("%s already has a familiar: %s.",
|
||||
unitname(um), unitname(uf));
|
||||
}
|
||||
else {
|
||||
set_familiar(um, u);
|
||||
}
|
||||
}
|
||||
else {
|
||||
log_error("%s seems to be a broken familiar with no trigger.", unitname(u));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int read_game(gamedata *data)
|
||||
{
|
||||
int p, nread;
|
||||
faction *f, **fp;
|
||||
region *r;
|
||||
|
@ -1671,6 +1516,9 @@ int read_game(gamedata *data) {
|
|||
|
||||
/* Burgen */
|
||||
READ_INT(store, &p);
|
||||
if (p > 0 && !r->land) {
|
||||
log_error("%s, uid=%d has %d buildings", regionname(r, NULL), r->uid, p);
|
||||
}
|
||||
bp = &r->buildings;
|
||||
|
||||
while (--p >= 0) {
|
||||
|
@ -1726,10 +1574,6 @@ int read_game(gamedata *data) {
|
|||
}
|
||||
read_borders(data);
|
||||
|
||||
/* Unaufgeloeste Zeiger initialisieren */
|
||||
log_debug("fixing unresolved references.");
|
||||
resolve();
|
||||
|
||||
log_debug("updating area information for lighthouses.");
|
||||
for (r = regions; r; r = r->next) {
|
||||
if (r->flags & RF_LIGHTHOUSE) {
|
||||
|
@ -1755,7 +1599,7 @@ int read_game(gamedata *data) {
|
|||
else {
|
||||
for (u = f->units; u; u = u->nextF) {
|
||||
if (data->version < SPELL_LEVEL_VERSION) {
|
||||
sc_mage *mage = get_mage(u);
|
||||
sc_mage *mage = get_mage_depr(u);
|
||||
if (mage) {
|
||||
faction *f = u->faction;
|
||||
int skl = effskill(u, SK_MAGIC, 0);
|
||||
|
@ -1783,6 +1627,11 @@ int read_game(gamedata *data) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (data->version < FAMILIAR_FIX_VERSION) {
|
||||
fix_familiars();
|
||||
}
|
||||
|
||||
if (loadplane || maxregions >= 0) {
|
||||
remove_empty_factions();
|
||||
}
|
||||
|
|
|
@ -43,7 +43,6 @@ extern "C" {
|
|||
/* TODO: is this *really* still in use? */
|
||||
extern int enc_gamedata;
|
||||
|
||||
int readorders(const char *filename);
|
||||
int readgame(const char *filename);
|
||||
int writegame(const char *filename);
|
||||
|
||||
|
|
|
@ -116,12 +116,15 @@ static void test_readwrite_region(CuTest * tc)
|
|||
gamedata data;
|
||||
storage store;
|
||||
region *r;
|
||||
const char * lipsum = "Lorem ipsum dolor sit amet";
|
||||
|
||||
test_setup();
|
||||
r = test_create_region(0, 0, 0);
|
||||
free(r->land->name);
|
||||
r->land->name = strdup(" Hodor ");
|
||||
CuAssertStrEquals(tc, " Hodor ", r->land->name);
|
||||
region_setinfo(r, lipsum);
|
||||
CuAssertStrEquals(tc, lipsum, r->land->display);
|
||||
mstream_init(&data.strm);
|
||||
gamedata_init(&data, &store, RELEASE_VERSION);
|
||||
write_region(&data, r);
|
||||
|
@ -132,6 +135,7 @@ static void test_readwrite_region(CuTest * tc)
|
|||
r = read_region(&data);
|
||||
CuAssertPtrNotNull(tc, r);
|
||||
CuAssertStrEquals(tc, "Hodor", r->land->name);
|
||||
CuAssertStrEquals(tc, lipsum, r->land->display);
|
||||
regions = r;
|
||||
|
||||
mstream_done(&data.strm);
|
||||
|
|
|
@ -277,6 +277,10 @@ int gift_items(unit * u, int flags)
|
|||
u->items = NULL;
|
||||
break;
|
||||
}
|
||||
else if (!u3) {
|
||||
/* pick a last-chance recipient: */
|
||||
u3 = u2;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (u->items && u3) {
|
||||
|
@ -644,9 +648,7 @@ void a_writesiege(const attrib * a, const void *owner, struct storage *store)
|
|||
|
||||
int a_readsiege(attrib * a, void *owner, gamedata *data)
|
||||
{
|
||||
int result = read_reference(&a->data.v, data, read_building_reference,
|
||||
resolve_building);
|
||||
if (result == 0 && !a->data.v) {
|
||||
if (read_building_reference(data, (building **)&a->data.v, NULL) <= 0) {
|
||||
return AT_READ_FAIL;
|
||||
}
|
||||
return AT_READ_OK;
|
||||
|
@ -747,25 +749,26 @@ void write_unit_reference(const unit * u, struct storage *store)
|
|||
WRITE_INT(store, (u && u->region) ? u->no : 0);
|
||||
}
|
||||
|
||||
int resolve_unit(variant id, void *address)
|
||||
void resolve_unit(unit *u)
|
||||
{
|
||||
unit *u = NULL;
|
||||
if (id.i != 0) {
|
||||
u = findunit(id.i);
|
||||
if (u == NULL) {
|
||||
*(unit **)address = NULL;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
*(unit **)address = u;
|
||||
return 0;
|
||||
resolve(RESOLVE_UNIT | u->no, u);
|
||||
}
|
||||
|
||||
variant read_unit_reference(gamedata *data)
|
||||
int read_unit_reference(gamedata * data, unit **up, resolve_fun fun)
|
||||
{
|
||||
variant var;
|
||||
READ_INT(data->store, &var.i);
|
||||
return var;
|
||||
int id;
|
||||
READ_INT(data->store, &id);
|
||||
if (id > 0) {
|
||||
*up = findunit(id);
|
||||
if (*up == NULL) {
|
||||
*up = NULL;
|
||||
ur_add(RESOLVE_UNIT | id, (void **)up, fun);
|
||||
}
|
||||
}
|
||||
else {
|
||||
*up = NULL;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
int get_level(const unit * u, skill_t id)
|
||||
|
@ -773,7 +776,7 @@ int get_level(const unit * u, skill_t id)
|
|||
assert(id != NOSKILL);
|
||||
if (skill_enabled(id)) {
|
||||
skill *sv = u->skills;
|
||||
while (sv != u->skills + u->skill_size) {
|
||||
while (sv != u->skills + u->skill_size && sv->id <= id) {
|
||||
if (sv->id == id) {
|
||||
return sv->level;
|
||||
}
|
||||
|
@ -795,7 +798,7 @@ void set_level(unit * u, skill_t sk, int value)
|
|||
remove_skill(u, sk);
|
||||
return;
|
||||
}
|
||||
while (sv != u->skills + u->skill_size) {
|
||||
while (sv != u->skills + u->skill_size && sv->id <= sk) {
|
||||
if (sv->id == sk) {
|
||||
sk_set(sv, value);
|
||||
return;
|
||||
|
@ -1060,7 +1063,7 @@ void clone_men(const unit * u, unit * dst, int n)
|
|||
transfer_curse(u, dst, n);
|
||||
}
|
||||
set_number(dst, dst->number + n);
|
||||
dst->hp += u->hp * dst->number / u->number;
|
||||
dst->hp += u->hp * n / u->number;
|
||||
assert(dst->hp >= dst->number);
|
||||
/* TODO: Das ist schnarchlahm! und gehoert nicht hierhin */
|
||||
a = a_find(dst->attribs, &at_effect);
|
||||
|
@ -1186,35 +1189,39 @@ void set_number(unit * u, int count)
|
|||
|
||||
void remove_skill(unit * u, skill_t sk)
|
||||
{
|
||||
skill *sv = u->skills;
|
||||
for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) {
|
||||
int i;
|
||||
skill *sv;
|
||||
for (i = 0; i != u->skill_size; ++i) {
|
||||
sv = u->skills + i;
|
||||
if (sv->id == sk) {
|
||||
skill *sl = u->skills + u->skill_size - 1;
|
||||
if (sl != sv) {
|
||||
*sv = *sl;
|
||||
}
|
||||
memmove(sv, sv + 1, (u->skill_size - i - 1) * sizeof(skill));
|
||||
--u->skill_size;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
skill *add_skill(unit * u, skill_t id)
|
||||
skill *add_skill(unit * u, skill_t sk)
|
||||
{
|
||||
skill *sv = u->skills;
|
||||
#ifndef NDEBUG
|
||||
for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) {
|
||||
assert(sv->id != id);
|
||||
skill *sv;
|
||||
int i;
|
||||
|
||||
for (i=0; i != u->skill_size; ++i) {
|
||||
sv = u->skills+i;
|
||||
if (sv->id >= sk) break;
|
||||
}
|
||||
u->skills = realloc(u->skills, (1 + u->skill_size) * sizeof(skill));
|
||||
sv = u->skills + i;
|
||||
if (i < u->skill_size) {
|
||||
assert(sv->id != sk);
|
||||
memmove(sv + 1, sv, sizeof(skill) * (u->skill_size - i));
|
||||
}
|
||||
#endif
|
||||
++u->skill_size;
|
||||
u->skills = realloc(u->skills, u->skill_size * sizeof(skill));
|
||||
sv = (u->skills + u->skill_size - 1);
|
||||
sv->level = 0;
|
||||
sv->weeks = 1;
|
||||
sv->old = 0;
|
||||
sv->id = id;
|
||||
if (id == SK_MAGIC && u->faction && !fval(u->faction, FFL_NPC)) {
|
||||
sv->id = sk;
|
||||
if (sk == SK_MAGIC && u->faction && !fval(u->faction, FFL_NPC)) {
|
||||
assert(u->number <= 1);
|
||||
assert(max_magicians(u->faction) >= u->number);
|
||||
}
|
||||
|
@ -1224,9 +1231,10 @@ skill *add_skill(unit * u, skill_t id)
|
|||
skill *unit_skill(const unit * u, skill_t sk)
|
||||
{
|
||||
skill *sv = u->skills;
|
||||
while (sv != u->skills + u->skill_size) {
|
||||
if (sv->id == sk)
|
||||
while (sv != u->skills + u->skill_size && sv->id <= sk) {
|
||||
if (sv->id == sk) {
|
||||
return sv;
|
||||
}
|
||||
++sv;
|
||||
}
|
||||
return NULL;
|
||||
|
@ -1235,7 +1243,7 @@ skill *unit_skill(const unit * u, skill_t sk)
|
|||
bool has_skill(const unit * u, skill_t sk)
|
||||
{
|
||||
skill *sv = u->skills;
|
||||
while (sv != u->skills + u->skill_size) {
|
||||
while (sv != u->skills + u->skill_size && sv->id <= sk) {
|
||||
if (sv->id == sk) {
|
||||
return (sv->level > 0);
|
||||
}
|
||||
|
@ -1484,14 +1492,6 @@ unit *create_unit(region * r, faction * f, int number, const struct race *urace,
|
|||
if (f) {
|
||||
assert(faction_alive(f));
|
||||
u_setfaction(u, f);
|
||||
|
||||
if (f->locale) {
|
||||
order *deford = default_order(f->locale);
|
||||
if (deford) {
|
||||
set_order(&u->thisorder, NULL);
|
||||
addlist(&u->orders, deford);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set_number(u, number);
|
||||
|
@ -1814,7 +1814,7 @@ void u_setrace(struct unit *u, const struct race *rc)
|
|||
|
||||
void unit_add_spell(unit * u, sc_mage * m, struct spell * sp, int level)
|
||||
{
|
||||
sc_mage *mage = m ? m : get_mage(u);
|
||||
sc_mage *mage = m ? m : get_mage_depr(u);
|
||||
|
||||
if (!mage) {
|
||||
log_debug("adding new spell %s to a previously non-mage unit %s\n", sp->sname, unitname(u));
|
||||
|
@ -1828,7 +1828,7 @@ void unit_add_spell(unit * u, sc_mage * m, struct spell * sp, int level)
|
|||
|
||||
struct spellbook * unit_get_spellbook(const struct unit * u)
|
||||
{
|
||||
sc_mage * mage = get_mage(u);
|
||||
sc_mage * mage = get_mage_depr(u);
|
||||
if (mage) {
|
||||
if (mage->spellbook) {
|
||||
return mage->spellbook;
|
||||
|
|
|
@ -19,7 +19,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
#ifndef H_KRNL_UNIT_H
|
||||
#define H_KRNL_UNIT_H
|
||||
|
||||
#include <util/variant.h>
|
||||
#include <util/resolve.h>
|
||||
#include "types.h"
|
||||
#include "skills.h"
|
||||
#include <stddef.h>
|
||||
|
@ -182,12 +182,13 @@ extern "C" {
|
|||
#define GIFT_FRIENDS 1<<1
|
||||
#define GIFT_PEASANTS 1<<2
|
||||
int gift_items(struct unit *u, int flags);
|
||||
void make_zombie(unit * u);
|
||||
void make_zombie(struct unit * u);
|
||||
|
||||
/* see resolve.h */
|
||||
int resolve_unit(variant data, void *address);
|
||||
#define RESOLVE_UNIT (TYP_UNIT << 24)
|
||||
void resolve_unit(struct unit *u);
|
||||
void write_unit_reference(const struct unit *u, struct storage *store);
|
||||
variant read_unit_reference(struct gamedata *data);
|
||||
int read_unit_reference(struct gamedata * data, struct unit **up, resolve_fun fun);
|
||||
|
||||
bool leave(struct unit *u, bool force);
|
||||
bool can_leave(struct unit *u);
|
||||
|
|
|
@ -31,7 +31,7 @@ static void test_remove_empty_units(CuTest *tc) {
|
|||
unit *u;
|
||||
int uid;
|
||||
|
||||
test_cleanup();
|
||||
test_setup();
|
||||
test_create_world();
|
||||
|
||||
u = test_create_unit(test_create_faction(test_create_race("human")), findregion(0, 0));
|
||||
|
@ -48,7 +48,7 @@ static void test_remove_empty_units_in_region(CuTest *tc) {
|
|||
unit *u;
|
||||
int uid;
|
||||
|
||||
test_cleanup();
|
||||
test_setup();
|
||||
test_create_world();
|
||||
|
||||
u = test_create_unit(test_create_faction(test_create_race("human")), findregion(0, 0));
|
||||
|
@ -69,7 +69,7 @@ static void test_remove_units_without_faction(CuTest *tc) {
|
|||
unit *u;
|
||||
int uid;
|
||||
|
||||
test_cleanup();
|
||||
test_setup();
|
||||
test_create_world();
|
||||
|
||||
u = test_create_unit(test_create_faction(test_create_race("human")), findregion(0, 0));
|
||||
|
@ -85,7 +85,7 @@ static void test_remove_units_with_dead_faction(CuTest *tc) {
|
|||
unit *u;
|
||||
int uid;
|
||||
|
||||
test_cleanup();
|
||||
test_setup();
|
||||
test_create_world();
|
||||
|
||||
u = test_create_unit(test_create_faction(test_create_race("human")), findregion(0, 0));
|
||||
|
@ -101,7 +101,7 @@ static void test_scale_number(CuTest *tc) {
|
|||
unit *u;
|
||||
const struct potion_type *ptype;
|
||||
|
||||
test_cleanup();
|
||||
test_setup();
|
||||
test_create_world();
|
||||
ptype = new_potiontype(it_get_or_create(rt_get_or_create("hodor")), 1);
|
||||
u = test_create_unit(test_create_faction(test_create_race("human")), findregion(0, 0));
|
||||
|
@ -122,7 +122,7 @@ static void test_scale_number(CuTest *tc) {
|
|||
static void test_unit_name(CuTest *tc) {
|
||||
unit *u;
|
||||
|
||||
test_cleanup();
|
||||
test_setup();
|
||||
test_create_world();
|
||||
u = test_create_unit(test_create_faction(test_create_race("human")), findregion(0, 0));
|
||||
renumber_unit(u, 666);
|
||||
|
@ -274,7 +274,7 @@ static void test_skill_familiar(CuTest *tc) {
|
|||
CuAssertIntEquals(tc, 6, effskill(mag, SK_PERCEPTION, 0));
|
||||
|
||||
/* make them mage and familiar to each other */
|
||||
CuAssertIntEquals(tc, true, create_newfamiliar(mag, fam));
|
||||
create_newfamiliar(mag, fam);
|
||||
|
||||
/* when they are in the same region, the mage gets half their skill as a bonus */
|
||||
CuAssertIntEquals(tc, 6, effskill(fam, SK_PERCEPTION, 0));
|
||||
|
@ -287,33 +287,11 @@ static void test_skill_familiar(CuTest *tc) {
|
|||
test_cleanup();
|
||||
}
|
||||
|
||||
static void test_age_familiar(CuTest *tc) {
|
||||
unit *mag, *fam;
|
||||
|
||||
test_cleanup();
|
||||
|
||||
mag = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
|
||||
fam = test_create_unit(mag->faction, test_create_region(0, 0, 0));
|
||||
CuAssertPtrEquals(tc, 0, get_familiar(mag));
|
||||
CuAssertPtrEquals(tc, 0, get_familiar_mage(fam));
|
||||
CuAssertIntEquals(tc, true, create_newfamiliar(mag, fam));
|
||||
CuAssertPtrEquals(tc, fam, get_familiar(mag));
|
||||
CuAssertPtrEquals(tc, mag, get_familiar_mage(fam));
|
||||
a_age(&fam->attribs, fam);
|
||||
a_age(&mag->attribs, mag);
|
||||
CuAssertPtrEquals(tc, fam, get_familiar(mag));
|
||||
CuAssertPtrEquals(tc, mag, get_familiar_mage(fam));
|
||||
set_number(fam, 0);
|
||||
a_age(&mag->attribs, mag);
|
||||
CuAssertPtrEquals(tc, 0, get_familiar(mag));
|
||||
test_cleanup();
|
||||
}
|
||||
|
||||
static void test_inside_building(CuTest *tc) {
|
||||
unit *u;
|
||||
building *b;
|
||||
|
||||
test_cleanup();
|
||||
test_setup();
|
||||
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
|
||||
b = test_create_building(u->region, 0);
|
||||
|
||||
|
@ -334,9 +312,50 @@ static void test_inside_building(CuTest *tc) {
|
|||
test_cleanup();
|
||||
}
|
||||
|
||||
static void test_skills(CuTest *tc) {
|
||||
unit *u;
|
||||
skill *sv;
|
||||
test_setup();
|
||||
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
|
||||
sv = add_skill(u, SK_ALCHEMY);
|
||||
CuAssertPtrNotNull(tc, sv);
|
||||
CuAssertPtrEquals(tc, sv, u->skills);
|
||||
CuAssertIntEquals(tc, 1, u->skill_size);
|
||||
CuAssertIntEquals(tc, SK_ALCHEMY, sv->id);
|
||||
CuAssertIntEquals(tc, 0, sv->level);
|
||||
CuAssertIntEquals(tc, 1, sv->weeks);
|
||||
CuAssertIntEquals(tc, 0, sv->old);
|
||||
sv = add_skill(u, SK_BUILDING);
|
||||
CuAssertPtrNotNull(tc, sv);
|
||||
CuAssertIntEquals(tc, 2, u->skill_size);
|
||||
CuAssertIntEquals(tc, SK_ALCHEMY, u->skills[0].id);
|
||||
CuAssertIntEquals(tc, SK_BUILDING, u->skills[1].id);
|
||||
sv = add_skill(u, SK_LONGBOW);
|
||||
CuAssertPtrNotNull(tc, sv);
|
||||
CuAssertPtrEquals(tc, sv, unit_skill(u, SK_LONGBOW));
|
||||
CuAssertIntEquals(tc, 3, u->skill_size);
|
||||
CuAssertIntEquals(tc, SK_ALCHEMY, u->skills[0].id);
|
||||
CuAssertIntEquals(tc, SK_LONGBOW, u->skills[1].id);
|
||||
CuAssertIntEquals(tc, SK_BUILDING, u->skills[2].id);
|
||||
CuAssertTrue(tc, !has_skill(u, SK_LONGBOW));
|
||||
set_level(u, SK_LONGBOW, 1);
|
||||
CuAssertTrue(tc, has_skill(u, SK_LONGBOW));
|
||||
remove_skill(u, SK_LONGBOW);
|
||||
CuAssertIntEquals(tc, SK_BUILDING, u->skills[1].id);
|
||||
CuAssertIntEquals(tc, 2, u->skill_size);
|
||||
remove_skill(u, SK_LONGBOW);
|
||||
CuAssertIntEquals(tc, SK_BUILDING, u->skills[1].id);
|
||||
CuAssertIntEquals(tc, 2, u->skill_size);
|
||||
remove_skill(u, SK_BUILDING);
|
||||
CuAssertIntEquals(tc, SK_ALCHEMY, u->skills[0].id);
|
||||
CuAssertIntEquals(tc, 1, u->skill_size);
|
||||
CuAssertTrue(tc, !has_skill(u, SK_LONGBOW));
|
||||
test_cleanup();
|
||||
}
|
||||
|
||||
static void test_limited_skills(CuTest *tc) {
|
||||
unit *u;
|
||||
test_cleanup();
|
||||
test_setup();
|
||||
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
|
||||
CuAssertIntEquals(tc, false, has_limited_skills(u));
|
||||
set_level(u, SK_ENTERTAINMENT, 1);
|
||||
|
@ -548,6 +567,27 @@ static void test_clone_men(CuTest *tc) {
|
|||
test_cleanup();
|
||||
}
|
||||
|
||||
static void test_transfermen(CuTest *tc) {
|
||||
unit *u1, *u2;
|
||||
region *r;
|
||||
faction *f;
|
||||
test_setup();
|
||||
r = test_create_region(0, 0, NULL);
|
||||
f = test_create_faction(NULL);
|
||||
u1 = test_create_unit(f, r);
|
||||
scale_number(u1, 3500);
|
||||
u2 = test_create_unit(f, r);
|
||||
scale_number(u2, 3500);
|
||||
CuAssertIntEquals(tc, 70000, u1->hp);
|
||||
CuAssertIntEquals(tc, 70000, u2->hp);
|
||||
transfermen(u1, u2, u1->number);
|
||||
CuAssertIntEquals(tc, 7000, u2->number);
|
||||
CuAssertIntEquals(tc, 140000, u2->hp);
|
||||
CuAssertIntEquals(tc, 0, u1->number);
|
||||
CuAssertIntEquals(tc, 0, u1->hp);
|
||||
test_cleanup();
|
||||
}
|
||||
|
||||
CuSuite *get_unit_suite(void)
|
||||
{
|
||||
CuSuite *suite = CuSuiteNew();
|
||||
|
@ -557,6 +597,7 @@ CuSuite *get_unit_suite(void)
|
|||
SUITE_ADD_TEST(suite, test_unit_name_from_race);
|
||||
SUITE_ADD_TEST(suite, test_update_monster_name);
|
||||
SUITE_ADD_TEST(suite, test_clone_men);
|
||||
SUITE_ADD_TEST(suite, test_transfermen);
|
||||
SUITE_ADD_TEST(suite, test_remove_unit);
|
||||
SUITE_ADD_TEST(suite, test_remove_empty_units);
|
||||
SUITE_ADD_TEST(suite, test_remove_units_without_faction);
|
||||
|
@ -568,8 +609,8 @@ CuSuite *get_unit_suite(void)
|
|||
SUITE_ADD_TEST(suite, test_skillmod);
|
||||
SUITE_ADD_TEST(suite, test_skill_hunger);
|
||||
SUITE_ADD_TEST(suite, test_skill_familiar);
|
||||
SUITE_ADD_TEST(suite, test_age_familiar);
|
||||
SUITE_ADD_TEST(suite, test_inside_building);
|
||||
SUITE_ADD_TEST(suite, test_skills);
|
||||
SUITE_ADD_TEST(suite, test_limited_skills);
|
||||
SUITE_ADD_TEST(suite, test_renumber_unit);
|
||||
SUITE_ADD_TEST(suite, test_name_unit);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
#ifndef ERESSEA_VERSION
|
||||
/* the version number, if it was not passed to make with -D */
|
||||
#define ERESSEA_VERSION "3.13.0"
|
||||
#define ERESSEA_VERSION "3.14.0"
|
||||
#endif
|
||||
|
||||
const char *eressea_version(void) {
|
||||
|
|
|
@ -960,7 +960,7 @@ static void add_spells(equipment * eq, xmlNodeSetPtr nsetItems)
|
|||
equipment_addspell(eq, name, level);
|
||||
}
|
||||
else {
|
||||
log_error("spell '%s' for equipment-set '%s' has no level\n", name, eq->name);
|
||||
log_error("spell '%s' for equipment-set '%s' has no level\n", name, equipment_name(eq));
|
||||
}
|
||||
xmlFree(propValue);
|
||||
}
|
||||
|
@ -980,7 +980,7 @@ static void add_skills(equipment * eq, xmlNodeSetPtr nsetSkills)
|
|||
assert(propValue != NULL);
|
||||
sk = findskill((const char *)propValue);
|
||||
if (sk == NOSKILL) {
|
||||
log_error("unknown skill '%s' in equipment-set %s\n", (const char *)propValue, eq->name);
|
||||
log_error("unknown skill '%s' in equipment-set %s\n", (const char *)propValue, equipment_name(eq));
|
||||
xmlFree(propValue);
|
||||
}
|
||||
else {
|
||||
|
@ -1044,7 +1044,7 @@ add_subsets(xmlDocPtr doc, equipment * eq, xmlNodeSetPtr nsetSubsets)
|
|||
}
|
||||
}
|
||||
if (totalChance > 1.0f) {
|
||||
log_error("total chance exceeds 1.0: %f in equipment set %s.\n", totalChance, eq->name);
|
||||
log_error("total chance exceeds 1.0: %f in equipment set %s.\n", totalChance, equipment_name(eq));
|
||||
}
|
||||
}
|
||||
xmlXPathFreeObject(xpathResult);
|
||||
|
@ -1069,9 +1069,13 @@ static int parse_equipment(xmlDocPtr doc)
|
|||
xmlChar *propName = xmlGetProp(node, BAD_CAST "name");
|
||||
|
||||
if (propName != NULL) {
|
||||
equipment *eq = get_or_create_equipment((const char *)propName);
|
||||
equipment *eq = get_equipment((const char *)propName);
|
||||
xmlXPathObjectPtr xpathResult;
|
||||
|
||||
if (!eq) {
|
||||
eq = create_equipment((const char *)propName);
|
||||
}
|
||||
|
||||
xpath->node = node;
|
||||
|
||||
xpathResult = xmlXPathEvalExpression(BAD_CAST "callback", xpath);
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include <kernel/config.h>
|
||||
#include "keyword.h"
|
||||
|
||||
#include <util/bsdstring.h>
|
||||
#include <util/language.h>
|
||||
#include <util/umlaut.h>
|
||||
#include <util/log.h>
|
||||
|
@ -20,7 +21,7 @@ const char * keyword(keyword_t kwd)
|
|||
if (!result[0]) {
|
||||
strcpy(result, "keyword::");
|
||||
}
|
||||
strcpy(result + 9, keywords[kwd]);
|
||||
strlcpy(result + 9, keywords[kwd], sizeof(result) - 9);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
218
src/laws.c
218
src/laws.c
|
@ -1559,11 +1559,11 @@ int display_cmd(unit * u, struct order *ord)
|
|||
break;
|
||||
|
||||
case P_REGION:
|
||||
if (u->faction != region_get_owner(r)) {
|
||||
if (!r->land || u->faction != region_get_owner(r)) {
|
||||
cmistake(u, ord, 147, MSG_EVENT);
|
||||
break;
|
||||
}
|
||||
s = &r->display;
|
||||
s = &r->land->display;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -3007,10 +3007,100 @@ int checkunitnumber(const faction * f, int add)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void maketemp_cmd(unit *u, order **olist)
|
||||
{
|
||||
order *makeord;
|
||||
int err = checkunitnumber(u->faction, 1);
|
||||
|
||||
makeord = *olist;
|
||||
if (err) {
|
||||
if (err == 1) {
|
||||
ADDMSG(&u->faction->msgs,
|
||||
msg_feedback(u, makeord,
|
||||
"too_many_units_in_alliance",
|
||||
"allowed", maxunits(u->faction)));
|
||||
}
|
||||
else {
|
||||
ADDMSG(&u->faction->msgs,
|
||||
msg_feedback(u, makeord,
|
||||
"too_many_units_in_faction",
|
||||
"allowed", maxunits(u->faction)));
|
||||
}
|
||||
*olist = makeord->next;
|
||||
makeord->next = NULL;
|
||||
free_order(makeord);
|
||||
while (*olist) {
|
||||
keyword_t kwd;
|
||||
order * ord = *olist;
|
||||
*olist = ord->next;
|
||||
ord->next = NULL;
|
||||
kwd = getkeyword(ord);
|
||||
free_order(ord);
|
||||
if (kwd == K_END) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
char token[128];
|
||||
const char *s;
|
||||
int alias;
|
||||
ship *sh;
|
||||
unit *u2;
|
||||
order **ordp, **oinsert;
|
||||
#ifndef NDEBUG
|
||||
keyword_t kwd = init_order(makeord);
|
||||
assert(kwd == K_MAKETEMP);
|
||||
#endif
|
||||
alias = getid();
|
||||
s = gettoken(token, sizeof(token));
|
||||
if (s && s[0] == '\0') {
|
||||
/* empty name? => generate one */
|
||||
s = NULL;
|
||||
}
|
||||
u2 = create_unit(u->region, u->faction, 0, u->faction->race, alias, s, u);
|
||||
fset(u2, UFL_ISNEW);
|
||||
a_add(&u2->attribs, a_new(&at_alias))->data.i = alias;
|
||||
sh = leftship(u);
|
||||
if (sh) {
|
||||
set_leftship(u2, sh);
|
||||
}
|
||||
setstatus(u2, u->status);
|
||||
|
||||
/* copy orders until K_END from u to u2 */
|
||||
ordp = &makeord->next;
|
||||
oinsert = &u2->orders;
|
||||
|
||||
while (*ordp) {
|
||||
order *ord = *ordp;
|
||||
*ordp = ord->next;
|
||||
if (getkeyword(ord) == K_END) {
|
||||
ord->next = NULL;
|
||||
free_order(ord);
|
||||
break;
|
||||
}
|
||||
*oinsert = ord;
|
||||
oinsert = &ord->next;
|
||||
*oinsert = NULL;
|
||||
}
|
||||
*olist = *ordp;
|
||||
makeord->next = NULL;
|
||||
free_order(makeord);
|
||||
|
||||
if (!u2->orders) {
|
||||
order *deford = default_order(u2->faction->locale);
|
||||
if (deford) {
|
||||
set_order(&u2->thisorder, NULL);
|
||||
addlist(&u2->orders, deford);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void new_units(void)
|
||||
{
|
||||
region *r;
|
||||
unit *u, *u2;
|
||||
unit *u;
|
||||
|
||||
/* neue einheiten werden gemacht und ihre befehle (bis zum "ende" zu
|
||||
* ihnen rueberkopiert, damit diese einheiten genauso wie die alten
|
||||
|
@ -3028,73 +3118,13 @@ void new_units(void)
|
|||
}
|
||||
|
||||
while (*ordp) {
|
||||
order *makeord = *ordp;
|
||||
if (getkeyword(makeord) == K_MAKETEMP) {
|
||||
char token[128], *name = NULL;
|
||||
const char *s;
|
||||
int alias;
|
||||
ship *sh;
|
||||
order **newordersp;
|
||||
int err = checkunitnumber(u->faction, 1);
|
||||
|
||||
if (err) {
|
||||
if (err == 1) {
|
||||
ADDMSG(&u->faction->msgs,
|
||||
msg_feedback(u, makeord,
|
||||
"too_many_units_in_alliance",
|
||||
"allowed", maxunits(u->faction)));
|
||||
}
|
||||
else {
|
||||
ADDMSG(&u->faction->msgs,
|
||||
msg_feedback(u, makeord,
|
||||
"too_many_units_in_faction",
|
||||
"allowed", maxunits(u->faction)));
|
||||
}
|
||||
ordp = &makeord->next;
|
||||
|
||||
while (*ordp) {
|
||||
order *ord = *ordp;
|
||||
if (getkeyword(ord) == K_END)
|
||||
break;
|
||||
*ordp = ord->next;
|
||||
ord->next = NULL;
|
||||
free_order(ord);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
init_order(makeord);
|
||||
alias = getid();
|
||||
|
||||
s = gettoken(token, sizeof(token));
|
||||
if (s && s[0]) {
|
||||
name = strdup(s);
|
||||
}
|
||||
u2 = create_unit(r, u->faction, 0, u->faction->race, alias, name, u);
|
||||
if (name != NULL)
|
||||
free(name); /* TODO: use a buffer on the stack instead? */
|
||||
fset(u2, UFL_ISNEW);
|
||||
|
||||
a_add(&u2->attribs, a_new(&at_alias))->data.i = alias;
|
||||
sh = leftship(u);
|
||||
if (sh) {
|
||||
set_leftship(u2, sh);
|
||||
}
|
||||
setstatus(u2, u->status);
|
||||
|
||||
ordp = &makeord->next;
|
||||
newordersp = &u2->orders;
|
||||
while (*ordp) {
|
||||
order *ord = *ordp;
|
||||
if (getkeyword(ord) == K_END)
|
||||
break;
|
||||
*ordp = ord->next;
|
||||
ord->next = NULL;
|
||||
*newordersp = ord;
|
||||
newordersp = &ord->next;
|
||||
}
|
||||
order *ord = *ordp;
|
||||
if (getkeyword(ord) == K_MAKETEMP) {
|
||||
maketemp_cmd(u, ordp);
|
||||
}
|
||||
else {
|
||||
ordp = &ord->next;
|
||||
}
|
||||
if (*ordp == makeord)
|
||||
ordp = &makeord->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3357,7 +3387,7 @@ static int faction_getmages(faction * f, unit ** results, int numresults)
|
|||
|
||||
for (u = f->units; u; u = u->nextF) {
|
||||
if (u->number > 0) {
|
||||
sc_mage *mage = get_mage(u);
|
||||
sc_mage *mage = get_mage_depr(u);
|
||||
if (mage) {
|
||||
int level = effskill(u, SK_MAGIC, 0);
|
||||
if (level > maxlevel) {
|
||||
|
@ -3416,7 +3446,7 @@ static void update_spells(void)
|
|||
show_new_spells(f, maxlevel, faction_get_spellbook(f));
|
||||
for (i = 0; i != MAXMAGES && mages[i]; ++i) {
|
||||
unit * u = mages[i];
|
||||
sc_mage *mage = get_mage(u);
|
||||
sc_mage *mage = get_mage_depr(u);
|
||||
if (mage && mage->spellbook) {
|
||||
int level = effskill(u, SK_MAGIC, 0);
|
||||
show_new_spells(f, level, mage->spellbook);
|
||||
|
@ -4254,7 +4284,6 @@ bool
|
|||
cansee(const faction * f, const region * r, const unit * u, int modifier)
|
||||
{
|
||||
int stealth, rings;
|
||||
unit *u2 = r->units;
|
||||
|
||||
if (u->faction == f || omniscient(f)) {
|
||||
return true;
|
||||
|
@ -4273,42 +4302,39 @@ cansee(const faction * f, const region * r, const unit * u, int modifier)
|
|||
}
|
||||
}
|
||||
|
||||
if (leftship(u))
|
||||
return true;
|
||||
|
||||
while (u2 && u2->faction != f)
|
||||
u2 = u2->next;
|
||||
if (u2 == NULL)
|
||||
return false;
|
||||
|
||||
/* simple visibility, just gotta have a unit in the region to see 'em */
|
||||
if (is_guard(u) || usiege(u) || u->building || u->ship) {
|
||||
/* simple visibility, just gotta have a viewer in the region to see 'em */
|
||||
if (leftship(u) || is_guard(u) || usiege(u) || u->building || u->ship) {
|
||||
return true;
|
||||
}
|
||||
|
||||
rings = invisible(u, NULL);
|
||||
stealth = eff_stealth(u, r) - modifier;
|
||||
|
||||
while (u2) {
|
||||
if (rings < u->number || invisible(u, u2) < u->number) {
|
||||
if (skill_enabled(SK_PERCEPTION)) {
|
||||
int observation = effskill(u2, SK_PERCEPTION, 0);
|
||||
unit *u2;
|
||||
for (u2 = r->units; u2; u2 = u2->next) {
|
||||
if (u2->faction == f) {
|
||||
if (rings < u->number || invisible(u, u2) < u->number) {
|
||||
if (skill_enabled(SK_PERCEPTION)) {
|
||||
int observation = effskill(u2, SK_PERCEPTION, 0);
|
||||
|
||||
if (observation >= stealth) {
|
||||
if (observation >= stealth) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* find next unit in our faction */
|
||||
do {
|
||||
u2 = u2->next;
|
||||
} while (u2 && u2->faction != f);
|
||||
}
|
||||
return false;
|
||||
|
||||
return (rings <= 0 && stealth <= 0);
|
||||
}
|
||||
|
||||
bool cansee_ex(const faction * f, const region * r, const unit * u, int modifier, seen_mode mode)
|
||||
{
|
||||
UNUSED_ARG(mode);
|
||||
return cansee(f, r, u, modifier);
|
||||
}
|
||||
|
||||
bool cansee_unit(const unit * u, const unit * target, int modifier)
|
||||
|
|
|
@ -98,7 +98,9 @@ extern "C" {
|
|||
|
||||
void nmr_warnings(void);
|
||||
|
||||
bool cansee(const struct faction *f, const struct region *r,
|
||||
bool cansee_ex(const struct faction * f, const struct region * r,
|
||||
const struct unit * u, int modifier, seen_mode mode);
|
||||
bool cansee(const struct faction * f, const struct region * r,
|
||||
const struct unit *u, int modifier);
|
||||
bool cansee_durchgezogen(const struct faction *f, const struct region *r,
|
||||
const struct unit *u, int modifier);
|
||||
|
|
174
src/laws.test.c
174
src/laws.test.c
|
@ -227,7 +227,7 @@ static void test_display_cmd(CuTest *tc) {
|
|||
|
||||
ord = create_order(K_DISPLAY, f->locale, "%s Hodor", LOC(f->locale, parameters[P_REGION]));
|
||||
CuAssertIntEquals(tc, 0, display_cmd(u, ord));
|
||||
CuAssertPtrEquals(tc, NULL, r->display);
|
||||
CuAssertPtrEquals(tc, NULL, r->land->display);
|
||||
free_order(ord);
|
||||
|
||||
test_cleanup();
|
||||
|
@ -428,6 +428,63 @@ static void test_unit_limit(CuTest * tc)
|
|||
test_cleanup();
|
||||
}
|
||||
|
||||
static void test_maketemp(CuTest * tc)
|
||||
{
|
||||
faction *f;
|
||||
unit *u, *u2;
|
||||
|
||||
test_setup();
|
||||
f = test_create_faction(NULL);
|
||||
u = test_create_unit(f, test_create_region(0, 0, NULL));
|
||||
|
||||
u->orders = create_order(K_MAKETEMP, f->locale, "1");
|
||||
u->orders->next = create_order(K_ENTERTAIN, f->locale, NULL);
|
||||
u->orders->next->next = create_order(K_END, f->locale, NULL);
|
||||
u->orders->next->next->next = create_order(K_TAX, f->locale, NULL);
|
||||
|
||||
new_units();
|
||||
CuAssertIntEquals(tc, 2, f->num_units);
|
||||
CuAssertPtrNotNull(tc, u2 = u->next);
|
||||
CuAssertPtrNotNull(tc, u2->orders);
|
||||
CuAssertPtrEquals(tc, NULL, u2->orders->next);
|
||||
CuAssertIntEquals(tc, K_ENTERTAIN, getkeyword(u2->orders));
|
||||
|
||||
CuAssertPtrNotNull(tc, u->orders);
|
||||
CuAssertPtrEquals(tc, NULL, u->orders->next);
|
||||
CuAssertIntEquals(tc, K_TAX, getkeyword(u->orders));
|
||||
test_cleanup();
|
||||
}
|
||||
|
||||
static void test_maketemp_default_order(CuTest * tc)
|
||||
{
|
||||
faction *f;
|
||||
unit *u, *u2;
|
||||
|
||||
test_setup();
|
||||
config_set("orders.default", "work");
|
||||
f = test_create_faction(NULL);
|
||||
u = test_create_unit(f, test_create_region(0, 0, NULL));
|
||||
|
||||
new_units();
|
||||
CuAssertIntEquals(tc, 1, f->num_units);
|
||||
|
||||
u->orders = create_order(K_MAKETEMP, f->locale, "1");
|
||||
u->orders->next = create_order(K_END, f->locale, NULL);
|
||||
u->orders->next->next = create_order(K_TAX, f->locale, NULL);
|
||||
|
||||
new_units();
|
||||
CuAssertIntEquals(tc, 2, f->num_units);
|
||||
CuAssertPtrNotNull(tc, u2 = u->next);
|
||||
CuAssertPtrNotNull(tc, u2->orders);
|
||||
CuAssertPtrEquals(tc, NULL, u2->orders->next);
|
||||
CuAssertIntEquals(tc, K_WORK, getkeyword(u2->orders));
|
||||
|
||||
CuAssertPtrNotNull(tc, u->orders);
|
||||
CuAssertPtrEquals(tc, NULL, u->orders->next);
|
||||
CuAssertIntEquals(tc, K_TAX, getkeyword(u->orders));
|
||||
test_cleanup();
|
||||
}
|
||||
|
||||
static void test_limit_new_units(CuTest * tc)
|
||||
{
|
||||
faction *f;
|
||||
|
@ -449,6 +506,8 @@ static void test_limit_new_units(CuTest * tc)
|
|||
CuAssertPtrNotNull(tc, u->next);
|
||||
CuAssertIntEquals(tc, 2, f->num_units);
|
||||
|
||||
CuAssertPtrEquals(tc, NULL, u->orders);
|
||||
u->orders = create_order(K_MAKETEMP, f->locale, "1");
|
||||
new_units();
|
||||
CuAssertIntEquals(tc, 2, f->num_units);
|
||||
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "too_many_units_in_faction"));
|
||||
|
@ -458,6 +517,8 @@ static void test_limit_new_units(CuTest * tc)
|
|||
config_set("rules.limit.faction", "3");
|
||||
config_set("rules.limit.alliance", "2");
|
||||
|
||||
CuAssertPtrEquals(tc, NULL, u->orders);
|
||||
u->orders = create_order(K_MAKETEMP, f->locale, "1");
|
||||
new_units();
|
||||
CuAssertIntEquals(tc, 2, f->num_units);
|
||||
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "too_many_units_in_alliance"));
|
||||
|
@ -466,6 +527,8 @@ static void test_limit_new_units(CuTest * tc)
|
|||
u = test_create_unit(test_create_faction(NULL), u->region);
|
||||
setalliance(u->faction, al);
|
||||
|
||||
CuAssertPtrEquals(tc, NULL, u->orders);
|
||||
u->orders = create_order(K_MAKETEMP, f->locale, "1");
|
||||
new_units();
|
||||
CuAssertIntEquals(tc, 2, f->num_units);
|
||||
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "too_many_units_in_alliance"));
|
||||
|
@ -1552,9 +1615,114 @@ static void test_armedmen(CuTest *tc) {
|
|||
test_cleanup();
|
||||
}
|
||||
|
||||
static void test_cansee(CuTest *tc) {
|
||||
unit *u, *u2;
|
||||
|
||||
test_setup();
|
||||
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
|
||||
u2 = test_create_unit(test_create_faction(0), u->region);
|
||||
|
||||
CuAssertTrue(tc, cansee(u->faction, u->region, u2, 0));
|
||||
|
||||
set_level(u2, SK_STEALTH, 1);
|
||||
CuAssertTrue(tc, !cansee(u->faction, u->region, u2, 0));
|
||||
|
||||
set_level(u, SK_PERCEPTION, 1);
|
||||
CuAssertTrue(tc, cansee(u->faction, u->region, u2, 0));
|
||||
|
||||
test_cleanup();
|
||||
}
|
||||
|
||||
static void test_cansee_spell(CuTest *tc) {
|
||||
unit *u2;
|
||||
faction *f;
|
||||
|
||||
test_setup();
|
||||
f = test_create_faction(0);
|
||||
u2 = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
|
||||
|
||||
CuAssertTrue(tc, cansee_ex(f, u2->region, u2, 0, seen_spell));
|
||||
CuAssertTrue(tc, cansee_ex(f, u2->region, u2, 0, seen_battle));
|
||||
|
||||
set_level(u2, SK_STEALTH, 1);
|
||||
CuAssertTrue(tc, !cansee_ex(f, u2->region, u2, 0, seen_spell));
|
||||
CuAssertTrue(tc, cansee_ex(f, u2->region, u2, 1, seen_spell));
|
||||
CuAssertTrue(tc, cansee_ex(f, u2->region, u2, 1, seen_battle));
|
||||
|
||||
test_cleanup();
|
||||
}
|
||||
|
||||
static void test_cansee_ring(CuTest *tc) {
|
||||
unit *u, *u2;
|
||||
item_type *itype[2];
|
||||
|
||||
test_setup();
|
||||
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
|
||||
u2 = test_create_unit(test_create_faction(0), u->region);
|
||||
scale_number(u2, 2);
|
||||
|
||||
itype[0] = test_create_itemtype("roi");
|
||||
itype[1] = test_create_itemtype("aots");
|
||||
CuAssertPtrNotNull(tc, get_resourcetype(R_RING_OF_INVISIBILITY));
|
||||
CuAssertPtrEquals(tc, itype[0]->rtype, (void *)get_resourcetype(R_RING_OF_INVISIBILITY));
|
||||
CuAssertPtrNotNull(tc, get_resourcetype(R_AMULET_OF_TRUE_SEEING));
|
||||
CuAssertPtrEquals(tc, itype[1]->rtype, (void *)get_resourcetype(R_AMULET_OF_TRUE_SEEING));
|
||||
|
||||
CuAssertTrue(tc, cansee(u->faction, u->region, u2, 0));
|
||||
|
||||
/* a single ring is not enough to hide two people */
|
||||
i_change(&u2->items, itype[0], 1);
|
||||
CuAssertTrue(tc, cansee(u->faction, u->region, u2, 0));
|
||||
|
||||
/* two rings can hide two people */
|
||||
i_change(&u2->items, itype[0], 1);
|
||||
CuAssertTrue(tc, !cansee(u->faction, u->region, u2, 0));
|
||||
|
||||
/* one amulet negates one of the two rings */
|
||||
i_change(&u->items, itype[1], 1);
|
||||
CuAssertTrue(tc, cansee(u->faction, u->region, u2, 0));
|
||||
|
||||
test_cleanup();
|
||||
}
|
||||
|
||||
static void test_cansee_sphere(CuTest *tc) {
|
||||
unit *u, *u2;
|
||||
item_type *itype[2];
|
||||
|
||||
test_setup();
|
||||
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
|
||||
u2 = test_create_unit(test_create_faction(0), u->region);
|
||||
|
||||
itype[0] = test_create_itemtype("sphereofinv");
|
||||
itype[1] = test_create_itemtype("aots");
|
||||
CuAssertPtrNotNull(tc, get_resourcetype(R_SPHERE_OF_INVISIBILITY));
|
||||
CuAssertPtrEquals(tc, itype[0]->rtype, (void *)get_resourcetype(R_SPHERE_OF_INVISIBILITY));
|
||||
CuAssertPtrNotNull(tc, get_resourcetype(R_AMULET_OF_TRUE_SEEING));
|
||||
CuAssertPtrEquals(tc, itype[1]->rtype, (void *)get_resourcetype(R_AMULET_OF_TRUE_SEEING));
|
||||
|
||||
CuAssertTrue(tc, cansee(u->faction, u->region, u2, 0));
|
||||
|
||||
/* a single sphere can hide 100 people */
|
||||
scale_number(u2, 100);
|
||||
i_change(&u2->items, itype[0], 1);
|
||||
CuAssertTrue(tc, !cansee(u->faction, u->region, u2, 0));
|
||||
|
||||
/* one single amulet negates it? */
|
||||
i_change(&u->items, itype[1], 1);
|
||||
CuAssertTrue(tc, cansee(u->faction, u->region, u2, 0));
|
||||
|
||||
/* number of people inside the sphere does not matter? */
|
||||
scale_number(u2, 99);
|
||||
CuAssertTrue(tc, cansee(u->faction, u->region, u2, 0));
|
||||
|
||||
test_cleanup();
|
||||
}
|
||||
|
||||
CuSuite *get_laws_suite(void)
|
||||
{
|
||||
CuSuite *suite = CuSuiteNew();
|
||||
SUITE_ADD_TEST(suite, test_maketemp_default_order);
|
||||
SUITE_ADD_TEST(suite, test_maketemp);
|
||||
SUITE_ADD_TEST(suite, test_nmr_warnings);
|
||||
SUITE_ADD_TEST(suite, test_ally_cmd);
|
||||
SUITE_ADD_TEST(suite, test_name_cmd);
|
||||
|
@ -1618,6 +1786,10 @@ CuSuite *get_laws_suite(void)
|
|||
SUITE_ADD_TEST(suite, test_immigration);
|
||||
SUITE_ADD_TEST(suite, test_demon_hunger);
|
||||
SUITE_ADD_TEST(suite, test_armedmen);
|
||||
SUITE_ADD_TEST(suite, test_cansee);
|
||||
SUITE_ADD_TEST(suite, test_cansee_ring);
|
||||
SUITE_ADD_TEST(suite, test_cansee_sphere);
|
||||
SUITE_ADD_TEST(suite, test_cansee_spell);
|
||||
|
||||
return suite;
|
||||
}
|
||||
|
|
217
src/magic.c
217
src/magic.c
|
@ -42,6 +42,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
#include <kernel/building.h>
|
||||
#include <kernel/callbacks.h>
|
||||
#include <kernel/curse.h>
|
||||
#include <kernel/equipment.h>
|
||||
#include <kernel/faction.h>
|
||||
#include <kernel/item.h>
|
||||
#include <kernel/messages.h>
|
||||
|
@ -322,17 +323,27 @@ attrib_type at_mage = {
|
|||
|
||||
bool is_mage(const unit * u)
|
||||
{
|
||||
return get_mage(u) != NULL;
|
||||
return get_mage_depr(u) != NULL;
|
||||
}
|
||||
|
||||
sc_mage *get_mage(const unit * u)
|
||||
{
|
||||
attrib *a = a_find(u->attribs, &at_mage);
|
||||
if (a) {
|
||||
return (sc_mage *)a->data.v;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sc_mage *get_mage_depr(const unit * u)
|
||||
{
|
||||
if (has_skill(u, SK_MAGIC)) {
|
||||
attrib *a = a_find(u->attribs, &at_mage);
|
||||
if (a)
|
||||
return a->data.v;
|
||||
if (a) {
|
||||
return (sc_mage *)a->data.v;
|
||||
}
|
||||
}
|
||||
return (sc_mage *)NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
|
@ -355,9 +366,7 @@ static int read_seenspell(attrib * a, void *owner, struct gamedata *data)
|
|||
}
|
||||
sp = find_spell(token);
|
||||
if (!sp) {
|
||||
log_warning("read_seenspell: could not find spell '%s'\n", token);
|
||||
}
|
||||
if (!sp) {
|
||||
log_info("read_seenspell: could not find spell '%s'\n", token);
|
||||
return AT_READ_FAIL;
|
||||
}
|
||||
a->data.v = sp;
|
||||
|
@ -479,12 +488,10 @@ sc_mage *create_mage(unit * u, magic_t mtyp)
|
|||
attrib *a;
|
||||
|
||||
a = a_find(u->attribs, &at_mage);
|
||||
if (a != NULL) {
|
||||
a_remove(&u->attribs, a);
|
||||
if (a == NULL) {
|
||||
a = a_add(&u->attribs, a_new(&at_mage));
|
||||
}
|
||||
a = a_add(&u->attribs, a_new(&at_mage));
|
||||
mage = a->data.v;
|
||||
|
||||
mage = (sc_mage *)a->data.v;
|
||||
mage->magietyp = mtyp;
|
||||
return mage;
|
||||
}
|
||||
|
@ -507,7 +514,7 @@ int u_hasspell(const unit *u, const struct spell *sp)
|
|||
|
||||
int get_combatspelllevel(const unit * u, int nr)
|
||||
{
|
||||
sc_mage *m = get_mage(u);
|
||||
sc_mage *m = get_mage_depr(u);
|
||||
|
||||
assert(nr < MAXCOMBATSPELLS);
|
||||
if (m) {
|
||||
|
@ -525,7 +532,7 @@ const spell *get_combatspell(const unit * u, int nr)
|
|||
sc_mage *m;
|
||||
|
||||
assert(nr < MAXCOMBATSPELLS);
|
||||
m = get_mage(u);
|
||||
m = get_mage_depr(u);
|
||||
if (m) {
|
||||
return m->combatspells[nr].sp;
|
||||
}
|
||||
|
@ -534,7 +541,7 @@ const spell *get_combatspell(const unit * u, int nr)
|
|||
|
||||
void set_combatspell(unit * u, spell * sp, struct order *ord, int level)
|
||||
{
|
||||
sc_mage *mage = get_mage(u);
|
||||
sc_mage *mage = get_mage_depr(u);
|
||||
int i = -1;
|
||||
|
||||
assert(mage || !"trying to set a combat spell for non-mage");
|
||||
|
@ -574,7 +581,7 @@ void unset_combatspell(unit * u, spell * sp)
|
|||
int nr = 0;
|
||||
int i;
|
||||
|
||||
m = get_mage(u);
|
||||
m = get_mage_depr(u);
|
||||
if (!m)
|
||||
return;
|
||||
|
||||
|
@ -610,7 +617,7 @@ int get_spellpoints(const unit * u)
|
|||
{
|
||||
sc_mage *m;
|
||||
|
||||
m = get_mage(u);
|
||||
m = get_mage_depr(u);
|
||||
if (!m)
|
||||
return 0;
|
||||
|
||||
|
@ -621,7 +628,7 @@ void set_spellpoints(unit * u, int sp)
|
|||
{
|
||||
sc_mage *m;
|
||||
|
||||
m = get_mage(u);
|
||||
m = get_mage_depr(u);
|
||||
if (!m)
|
||||
return;
|
||||
|
||||
|
@ -638,7 +645,7 @@ int change_spellpoints(unit * u, int mp)
|
|||
sc_mage *m;
|
||||
int sp;
|
||||
|
||||
m = get_mage(u);
|
||||
m = get_mage_depr(u);
|
||||
if (!m) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -657,7 +664,7 @@ static int get_spchange(const unit * u)
|
|||
{
|
||||
sc_mage *m;
|
||||
|
||||
m = get_mage(u);
|
||||
m = get_mage_depr(u);
|
||||
if (!m)
|
||||
return 0;
|
||||
|
||||
|
@ -711,7 +718,7 @@ int change_maxspellpoints(unit * u, int csp)
|
|||
{
|
||||
sc_mage *m;
|
||||
|
||||
m = get_mage(u);
|
||||
m = get_mage_depr(u);
|
||||
if (!m) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -729,7 +736,7 @@ int countspells(unit * u, int step)
|
|||
sc_mage *m;
|
||||
int count;
|
||||
|
||||
m = get_mage(u);
|
||||
m = get_mage_depr(u);
|
||||
if (!m)
|
||||
return 0;
|
||||
|
||||
|
@ -1313,7 +1320,7 @@ bool fumble(region * r, unit * u, const spell * sp, int cast_grade)
|
|||
}
|
||||
|
||||
/* CHAOSPATZERCHANCE 10 : +10% Chance zu Patzern */
|
||||
mage = get_mage(u);
|
||||
mage = get_mage_depr(u);
|
||||
if (mage->magietyp == M_DRAIG) {
|
||||
fumble_chance += CHAOSPATZERCHANCE;
|
||||
}
|
||||
|
@ -2139,16 +2146,6 @@ void free_castorders(castorder * co)
|
|||
return;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
/***
|
||||
** at_familiarmage
|
||||
**/
|
||||
|
||||
typedef struct familiar_data {
|
||||
unit *mage;
|
||||
unit *familiar;
|
||||
} famililar_data;
|
||||
|
||||
bool is_familiar(const unit * u)
|
||||
{
|
||||
attrib *a = a_find(u->attribs, &at_familiarmage);
|
||||
|
@ -2181,7 +2178,7 @@ static int sm_familiar(const unit * u, const region * r, skill_t sk, int value)
|
|||
}
|
||||
}
|
||||
|
||||
static void set_familiar(unit * mage, unit * familiar)
|
||||
void set_familiar(unit * mage, unit * familiar)
|
||||
{
|
||||
/* if the skill modifier for the mage does not yet exist, add it */
|
||||
attrib *a = a_find(mage->attribs, &at_skillmod);
|
||||
|
@ -2192,10 +2189,8 @@ static void set_familiar(unit * mage, unit * familiar)
|
|||
a = a->next;
|
||||
}
|
||||
if (a == NULL) {
|
||||
attrib *an = a_add(&mage->attribs, a_new(&at_skillmod));
|
||||
skillmod_data *smd = (skillmod_data *)an->data.v;
|
||||
smd->special = sm_familiar;
|
||||
smd->skill = NOSKILL;
|
||||
a = make_skillmod(NOSKILL, sm_familiar, 0.0, 0);
|
||||
a_add(&mage->attribs, a);
|
||||
}
|
||||
|
||||
a = a_find(mage->attribs, &at_familiar);
|
||||
|
@ -2203,17 +2198,19 @@ static void set_familiar(unit * mage, unit * familiar)
|
|||
a = a_add(&mage->attribs, a_new(&at_familiar));
|
||||
a->data.v = familiar;
|
||||
}
|
||||
else
|
||||
else {
|
||||
assert(!a->data.v || a->data.v == familiar);
|
||||
/* TODO: Diese Attribute beim Tod des Familiars entfernen: */
|
||||
}
|
||||
|
||||
/* TODO: Diese Attribute beim Tod des Familiars entfernen: */
|
||||
a = a_find(familiar->attribs, &at_familiarmage);
|
||||
if (a == NULL) {
|
||||
a = a_add(&familiar->attribs, a_new(&at_familiarmage));
|
||||
a->data.v = mage;
|
||||
}
|
||||
else
|
||||
else {
|
||||
assert(!a->data.v || a->data.v == mage);
|
||||
}
|
||||
}
|
||||
|
||||
void remove_familiar(unit * mage)
|
||||
|
@ -2229,70 +2226,52 @@ void remove_familiar(unit * mage)
|
|||
while (a && a->type == &at_skillmod) {
|
||||
an = a->next;
|
||||
smd = (skillmod_data *)a->data.v;
|
||||
if (smd->special == sm_familiar)
|
||||
if (smd->special == sm_familiar) {
|
||||
a_remove(&mage->attribs, a);
|
||||
}
|
||||
a = an;
|
||||
}
|
||||
}
|
||||
|
||||
bool create_newfamiliar(unit * mage, unit * familiar)
|
||||
void create_newfamiliar(unit * mage, unit * fam)
|
||||
{
|
||||
/* if the skill modifier for the mage does not yet exist, add it */
|
||||
attrib *a;
|
||||
attrib *afam = a_find(mage->attribs, &at_familiar);
|
||||
attrib *amage = a_find(familiar->attribs, &at_familiarmage);
|
||||
/* skills and spells: */
|
||||
const struct equipment *eq;
|
||||
char eqname[64];
|
||||
const race *rc = u_race(fam);
|
||||
|
||||
if (afam == NULL) {
|
||||
afam = a_add(&mage->attribs, a_new(&at_familiar));
|
||||
}
|
||||
afam->data.v = familiar;
|
||||
if (amage == NULL) {
|
||||
amage = a_add(&familiar->attribs, a_new(&at_familiarmage));
|
||||
}
|
||||
amage->data.v = mage;
|
||||
set_familiar(mage, fam);
|
||||
|
||||
snprintf(eqname, sizeof(eqname), "fam_%s", rc->_name);
|
||||
eq = get_equipment(eqname);
|
||||
if (eq != NULL) {
|
||||
equip_unit(fam, eq);
|
||||
}
|
||||
else {
|
||||
log_info("could not perform initialization for familiar %s.\n", rc->_name);
|
||||
}
|
||||
/* TODO: Diese Attribute beim Tod des Familiars entfernen: */
|
||||
/* Wenn der Magier stirbt, dann auch der Vertraute */
|
||||
add_trigger(&mage->attribs, "destroy", trigger_killunit(familiar));
|
||||
add_trigger(&mage->attribs, "destroy", trigger_killunit(fam));
|
||||
/* Wenn der Vertraute stirbt, dann bekommt der Magier einen Schock */
|
||||
add_trigger(&familiar->attribs, "destroy", trigger_shock(mage));
|
||||
|
||||
a = a_find(mage->attribs, &at_skillmod);
|
||||
while (a && a->type == &at_skillmod) {
|
||||
skillmod_data *smd = (skillmod_data *)a->data.v;
|
||||
if (smd->special == sm_familiar)
|
||||
break;
|
||||
a = a->next;
|
||||
}
|
||||
if (a == NULL) {
|
||||
attrib *an = a_add(&mage->attribs, a_new(&at_skillmod));
|
||||
skillmod_data *smd = (skillmod_data *)an->data.v;
|
||||
smd->special = sm_familiar;
|
||||
smd->skill = NOSKILL;
|
||||
}
|
||||
return true;
|
||||
add_trigger(&fam->attribs, "destroy", trigger_shock(mage));
|
||||
}
|
||||
|
||||
static int resolve_familiar(variant data, void *addr)
|
||||
{
|
||||
unit *familiar;
|
||||
int result = resolve_unit(data, &familiar);
|
||||
if (result == 0 && familiar) {
|
||||
static void * resolve_familiar(int id, void *data) {
|
||||
if (data) {
|
||||
unit *familiar = (unit *)data;
|
||||
attrib *a = a_find(familiar->attribs, &at_familiarmage);
|
||||
if (a != NULL && a->data.v) {
|
||||
unit *mage = (unit *)a->data.v;
|
||||
set_familiar(mage, familiar);
|
||||
}
|
||||
}
|
||||
*(unit **)addr = familiar;
|
||||
return result;
|
||||
return data;
|
||||
}
|
||||
|
||||
static int read_familiar(attrib * a, void *owner, struct gamedata *data)
|
||||
{
|
||||
int result =
|
||||
read_reference(&a->data.v, data, read_unit_reference, resolve_familiar);
|
||||
if (result == 0 && a->data.v == NULL) {
|
||||
if (read_unit_reference(data, (unit **)&a->data.v, resolve_familiar) <= 0) {
|
||||
return AT_READ_FAIL;
|
||||
}
|
||||
return AT_READ_OK;
|
||||
|
@ -2357,53 +2336,42 @@ unit *has_clone(unit * mage)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static int resolve_clone(variant data, void *addr)
|
||||
{
|
||||
unit *clone;
|
||||
int result = resolve_unit(data, &clone);
|
||||
if (result == 0 && clone) {
|
||||
static void * resolve_clone(int id, void *data) {
|
||||
if (data) {
|
||||
unit *clone = (unit *)data;
|
||||
attrib *a = a_find(clone->attribs, &at_clonemage);
|
||||
if (a != NULL && a->data.v) {
|
||||
unit *mage = (unit *)a->data.v;
|
||||
set_clone(mage, clone);
|
||||
}
|
||||
}
|
||||
*(unit **)addr = clone;
|
||||
return result;
|
||||
return data;
|
||||
}
|
||||
|
||||
static int read_clone(attrib * a, void *owner, struct gamedata *data)
|
||||
{
|
||||
int result =
|
||||
read_reference(&a->data.v, data, read_unit_reference, resolve_clone);
|
||||
if (result == 0 && a->data.v == NULL) {
|
||||
if (read_unit_reference(data, (unit **)&a->data.v, resolve_clone) <= 0) {
|
||||
return AT_READ_FAIL;
|
||||
}
|
||||
return AT_READ_OK;
|
||||
}
|
||||
|
||||
/* mages */
|
||||
|
||||
static int resolve_mage(variant data, void *addr)
|
||||
{
|
||||
unit *mage;
|
||||
int result = resolve_unit(data, &mage);
|
||||
if (result == 0 && mage) {
|
||||
static void * resolve_mage(int id, void *data) {
|
||||
if (data) {
|
||||
unit *mage = (unit *)data;
|
||||
attrib *a = a_find(mage->attribs, &at_familiar);
|
||||
if (a != NULL && a->data.v) {
|
||||
unit *familiar = (unit *)a->data.v;
|
||||
set_familiar(mage, familiar);
|
||||
}
|
||||
}
|
||||
*(unit **)addr = mage;
|
||||
return result;
|
||||
return data;
|
||||
}
|
||||
|
||||
static int read_magician(attrib * a, void *owner, struct gamedata *data)
|
||||
{
|
||||
int result =
|
||||
read_reference(&a->data.v, data, read_unit_reference, resolve_mage);
|
||||
if (result == 0 && a->data.v == NULL) {
|
||||
if (read_unit_reference(data, (unit **)&a->data.v, resolve_mage) <= 0) {
|
||||
return AT_READ_FAIL;
|
||||
}
|
||||
return AT_READ_OK;
|
||||
|
@ -3019,30 +2987,36 @@ int cast_spell(struct castorder *co)
|
|||
|
||||
static critbit_tree cb_spellbooks;
|
||||
|
||||
#define SBNAMELEN 16
|
||||
|
||||
typedef struct sb_entry {
|
||||
char key[SBNAMELEN];
|
||||
spellbook *value;
|
||||
} sb_entry;
|
||||
|
||||
spellbook * get_spellbook(const char * name)
|
||||
{
|
||||
char buffer[64];
|
||||
spellbook * result;
|
||||
void * match;
|
||||
size_t len = strlen(name);
|
||||
const void * match;
|
||||
|
||||
if (cb_find_prefix(&cb_spellbooks, name, strlen(name), &match, 1, 0) > 0) {
|
||||
cb_get_kv(match, &result, sizeof(result));
|
||||
if (len >= SBNAMELEN) {
|
||||
log_error("spellbook name is longer than %d bytes: %s", SBNAMELEN-1, name);
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
size_t len = strlen(name);
|
||||
result = create_spellbook(name);
|
||||
assert(strlen(name) + sizeof(result) < sizeof(buffer));
|
||||
len = cb_new_kv(name, len, &result, sizeof(result), buffer);
|
||||
if (cb_insert(&cb_spellbooks, buffer, len) == CB_EXISTS) {
|
||||
|
||||
match = cb_find_str(&cb_spellbooks, name);
|
||||
if (!match) {
|
||||
sb_entry ent;
|
||||
memset(ent.key, 0, SBNAMELEN);
|
||||
memcpy(ent.key, name, len);
|
||||
ent.value = create_spellbook(name);
|
||||
if (cb_insert(&cb_spellbooks, &ent, sizeof(ent)) == CB_EXISTS) {
|
||||
log_error("cb_insert failed although cb_find returned nothing for spellbook=%s", name);
|
||||
assert(!"should not happen");
|
||||
}
|
||||
result = 0;
|
||||
if (cb_find_prefix(&cb_spellbooks, name, strlen(name), &match, 1, 0) > 0) {
|
||||
cb_get_kv(match, &result, sizeof(result));
|
||||
}
|
||||
return ent.value;
|
||||
}
|
||||
return result;
|
||||
return ((const sb_entry *)match)->value;
|
||||
}
|
||||
|
||||
void free_spellbook(spellbook *sb) {
|
||||
|
@ -3051,9 +3025,8 @@ void free_spellbook(spellbook *sb) {
|
|||
}
|
||||
|
||||
static int free_spellbook_cb(const void *match, const void *key, size_t keylen, void *data) {
|
||||
spellbook *sb;
|
||||
cb_get_kv(match, &sb, sizeof(sb));
|
||||
free_spellbook(sb);
|
||||
const sb_entry *ent = (const sb_entry *)match;
|
||||
free_spellbook(ent->value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
29
src/magic.h
29
src/magic.h
|
@ -38,6 +38,10 @@ extern "C" {
|
|||
#define IRONGOLEM_CRUMBLE 15 /* monatlich Chance zu zerfallen */
|
||||
#define STONEGOLEM_CRUMBLE 10 /* monatlich Chance zu zerfallen */
|
||||
|
||||
extern const char *magic_school[MAXMAGIETYP];
|
||||
extern struct attrib_type at_familiar;
|
||||
extern struct attrib_type at_familiarmage;
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
/* Spruchparameter
|
||||
* Wir suchen beim Parsen des Befehls erstmal nach lokalen Objekten,
|
||||
|
@ -82,11 +86,6 @@ extern "C" {
|
|||
#define TARGET_RESISTS (1<<0)
|
||||
#define TARGET_NOTFOUND (1<<1)
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
/* Magierichtungen */
|
||||
|
||||
extern const char *magic_school[MAXMAGIETYP];
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
/* Magier:
|
||||
* - Magierichtung
|
||||
|
@ -222,6 +221,7 @@ extern "C" {
|
|||
/* macht die struct unit zu einem neuen Magier: legt die struct u->mage an
|
||||
* und initialisiert den Magiertypus mit mtyp. */
|
||||
sc_mage *get_mage(const struct unit *u);
|
||||
sc_mage *get_mage_depr(const struct unit *u);
|
||||
/* gibt u->mage zurück, bei nicht-Magiern *NULL */
|
||||
bool is_mage(const struct unit *u);
|
||||
/* gibt true, wenn u->mage gesetzt. */
|
||||
|
@ -324,16 +324,15 @@ extern "C" {
|
|||
|
||||
/* Sprüche in der struct region */
|
||||
/* (sind in curse) */
|
||||
extern struct unit *get_familiar(const struct unit *u);
|
||||
extern struct unit *get_familiar_mage(const struct unit *u);
|
||||
extern struct unit *get_clone(const struct unit *u);
|
||||
extern struct unit *get_clone_mage(const struct unit *u);
|
||||
extern struct attrib_type at_familiar;
|
||||
extern struct attrib_type at_familiarmage;
|
||||
extern void remove_familiar(struct unit *mage);
|
||||
extern bool create_newfamiliar(struct unit *mage, struct unit *familiar);
|
||||
extern void create_newclone(struct unit *mage, struct unit *familiar);
|
||||
extern struct unit *has_clone(struct unit *mage);
|
||||
void set_familiar(struct unit * mage, struct unit * familiar);
|
||||
struct unit *get_familiar(const struct unit *u);
|
||||
struct unit *get_familiar_mage(const struct unit *u);
|
||||
struct unit *get_clone(const struct unit *u);
|
||||
struct unit *get_clone_mage(const struct unit *u);
|
||||
void remove_familiar(struct unit *mage);
|
||||
void create_newfamiliar(struct unit *mage, struct unit *familiar);
|
||||
void create_newclone(struct unit *mage, struct unit *familiar);
|
||||
struct unit *has_clone(struct unit *mage);
|
||||
|
||||
const char *spell_info(const struct spell *sp,
|
||||
const struct locale *lang);
|
||||
|
|
156
src/magic.test.c
156
src/magic.test.c
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include <kernel/building.h>
|
||||
#include <kernel/race.h>
|
||||
#include <kernel/equipment.h>
|
||||
#include <kernel/faction.h>
|
||||
#include <kernel/order.h>
|
||||
#include <kernel/item.h>
|
||||
|
@ -51,7 +52,18 @@ void test_updatespells(CuTest * tc)
|
|||
test_cleanup();
|
||||
}
|
||||
|
||||
void test_spellbooks(CuTest * tc)
|
||||
static void test_get_spellbook(CuTest * tc)
|
||||
{
|
||||
spellbook *sb;
|
||||
|
||||
test_setup();
|
||||
CuAssertPtrNotNull(tc, sb = get_spellbook("hodorhodorhodor"));
|
||||
CuAssertPtrEquals(tc, sb, get_spellbook("hodorhodorhodor"));
|
||||
CuAssertTrue(tc, sb != get_spellbook("hodor"));
|
||||
test_cleanup();
|
||||
}
|
||||
|
||||
static void test_spellbooks(CuTest * tc)
|
||||
{
|
||||
spell *sp;
|
||||
spellbook *herp, *derp;
|
||||
|
@ -445,24 +457,6 @@ static void test_max_spellpoints(CuTest *tc) {
|
|||
test_cleanup();
|
||||
}
|
||||
|
||||
static void test_familiar_mage(CuTest *tc) {
|
||||
unit *um, *uf, *ut;
|
||||
test_setup();
|
||||
um = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
|
||||
uf = test_create_unit(um->faction, um->region);
|
||||
ut = test_create_unit(um->faction, um->region);
|
||||
set_number(ut, 0);
|
||||
CuAssertTrue(tc, create_newfamiliar(um, uf));
|
||||
CuAssertTrue(tc, is_familiar(uf));
|
||||
CuAssertTrue(tc, !is_familiar(um));
|
||||
CuAssertPtrEquals(tc, um, get_familiar_mage(uf));
|
||||
CuAssertPtrEquals(tc, uf, get_familiar(um));
|
||||
|
||||
CuAssertPtrEquals(tc, NULL, give_men(1, um, ut, NULL));
|
||||
CuAssertPtrEquals(tc, ut, get_familiar_mage(uf));
|
||||
test_cleanup();
|
||||
}
|
||||
|
||||
static void test_illusioncastle(CuTest *tc)
|
||||
{
|
||||
building *b;
|
||||
|
@ -484,12 +478,135 @@ static void test_illusioncastle(CuTest *tc)
|
|||
test_cleanup();
|
||||
}
|
||||
|
||||
static void test_is_mage(CuTest *tc) {
|
||||
unit *u;
|
||||
sc_mage *mage;
|
||||
|
||||
test_setup();
|
||||
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
|
||||
CuAssertPtrEquals(tc, NULL, get_mage(u));
|
||||
CuAssertTrue(tc, !is_mage(u));
|
||||
set_level(u, SK_MAGIC, 1);
|
||||
CuAssertTrue(tc, !is_mage(u));
|
||||
CuAssertPtrEquals(tc, NULL, get_mage(u));
|
||||
CuAssertPtrNotNull(tc, mage = create_mage(u, M_CERDDOR));
|
||||
CuAssertPtrEquals(tc, mage, get_mage(u));
|
||||
CuAssertTrue(tc, is_mage(u));
|
||||
test_cleanup();
|
||||
}
|
||||
|
||||
static void test_get_mage(CuTest *tc) {
|
||||
unit *u;
|
||||
sc_mage *mage;
|
||||
|
||||
test_setup();
|
||||
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
|
||||
CuAssertPtrEquals(tc, NULL, get_mage(u));
|
||||
CuAssertPtrEquals(tc, NULL, get_mage_depr(u));
|
||||
CuAssertPtrNotNull(tc, mage = create_mage(u, M_CERDDOR));
|
||||
CuAssertPtrEquals(tc, mage, get_mage(u));
|
||||
CuAssertPtrEquals(tc, NULL, get_mage_depr(u));
|
||||
set_level(u, SK_MAGIC, 1);
|
||||
CuAssertPtrEquals(tc, mage, get_mage(u));
|
||||
CuAssertPtrEquals(tc, mage, get_mage_depr(u));
|
||||
test_cleanup();
|
||||
}
|
||||
|
||||
static void test_familiar_set(CuTest *tc) {
|
||||
unit *mag, *fam;
|
||||
|
||||
test_setup();
|
||||
|
||||
mag = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
|
||||
fam = test_create_unit(mag->faction, test_create_region(0, 0, 0));
|
||||
CuAssertPtrEquals(tc, NULL, get_familiar(mag));
|
||||
CuAssertPtrEquals(tc, NULL, get_familiar_mage(fam));
|
||||
CuAssertPtrEquals(tc, NULL, a_find(mag->attribs, &at_skillmod));
|
||||
set_familiar(mag, fam);
|
||||
CuAssertPtrEquals(tc, fam, get_familiar(mag));
|
||||
CuAssertPtrEquals(tc, mag, get_familiar_mage(fam));
|
||||
CuAssertPtrNotNull(tc, a_find(mag->attribs, &at_skillmod));
|
||||
remove_familiar(mag);
|
||||
CuAssertPtrEquals(tc, NULL, get_familiar(mag));
|
||||
CuAssertPtrEquals(tc, NULL, a_find(mag->attribs, &at_skillmod));
|
||||
test_cleanup();
|
||||
}
|
||||
|
||||
static void test_familiar_age(CuTest *tc) {
|
||||
unit *mag, *fam;
|
||||
|
||||
test_setup();
|
||||
|
||||
mag = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
|
||||
fam = test_create_unit(mag->faction, test_create_region(0, 0, 0));
|
||||
set_familiar(mag, fam);
|
||||
CuAssertPtrEquals(tc, fam, get_familiar(mag));
|
||||
CuAssertPtrEquals(tc, mag, get_familiar_mage(fam));
|
||||
a_age(&fam->attribs, fam);
|
||||
a_age(&mag->attribs, mag);
|
||||
CuAssertPtrEquals(tc, fam, get_familiar(mag));
|
||||
CuAssertPtrEquals(tc, mag, get_familiar_mage(fam));
|
||||
set_number(fam, 0);
|
||||
a_age(&mag->attribs, mag);
|
||||
CuAssertPtrEquals(tc, NULL, get_familiar(mag));
|
||||
test_cleanup();
|
||||
}
|
||||
|
||||
static void test_familiar_equip(CuTest *tc) {
|
||||
unit *mag, *u;
|
||||
equipment *eq;
|
||||
const item_type * itype;
|
||||
spell *sp;
|
||||
sc_mage * mage;
|
||||
|
||||
test_setup();
|
||||
|
||||
itype = test_create_itemtype("horse");
|
||||
CuAssertPtrNotNull(tc, itype);
|
||||
sp = create_spell("testspell");
|
||||
CuAssertPtrNotNull(tc, sp);
|
||||
|
||||
eq = get_or_create_equipment("fam_human");
|
||||
equipment_setitem(eq, itype, "1");
|
||||
equipment_setskill(eq, SK_ENTERTAINMENT, "5");
|
||||
equipment_addspell(eq, sp->sname, 1);
|
||||
|
||||
mag = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
|
||||
u = test_create_unit(mag->faction, test_create_region(0, 0, 0));
|
||||
set_familiar(mag, u);
|
||||
create_newfamiliar(mag, u);
|
||||
CuAssertIntEquals(tc, 1, i_get(u->items, itype));
|
||||
CuAssertIntEquals(tc, 5, get_level(u, SK_ENTERTAINMENT));
|
||||
CuAssertIntEquals(tc, 0, get_level(u, SK_MAGIC));
|
||||
|
||||
mage = get_mage(u);
|
||||
CuAssertPtrNotNull(tc, mage);
|
||||
CuAssertPtrNotNull(tc, mage->spellbook);
|
||||
set_level(u, SK_MAGIC, 1);
|
||||
CuAssertPtrEquals(tc, mage, get_mage_depr(u));
|
||||
CuAssertTrue(tc, u_hasspell(u, sp));
|
||||
|
||||
test_cleanup();
|
||||
}
|
||||
|
||||
CuSuite *get_familiar_suite(void)
|
||||
{
|
||||
CuSuite *suite = CuSuiteNew();
|
||||
SUITE_ADD_TEST(suite, test_familiar_equip);
|
||||
SUITE_ADD_TEST(suite, test_familiar_set);
|
||||
SUITE_ADD_TEST(suite, test_familiar_age);
|
||||
return suite;
|
||||
}
|
||||
|
||||
CuSuite *get_magic_suite(void)
|
||||
{
|
||||
CuSuite *suite = CuSuiteNew();
|
||||
SUITE_ADD_TEST(suite, test_is_mage);
|
||||
SUITE_ADD_TEST(suite, test_get_mage);
|
||||
SUITE_ADD_TEST(suite, test_multi_cast);
|
||||
SUITE_ADD_TEST(suite, test_updatespells);
|
||||
SUITE_ADD_TEST(suite, test_spellbooks);
|
||||
SUITE_ADD_TEST(suite, test_get_spellbook);
|
||||
SUITE_ADD_TEST(suite, test_pay_spell);
|
||||
SUITE_ADD_TEST(suite, test_pay_spell_failure);
|
||||
SUITE_ADD_TEST(suite, test_getspell_unit);
|
||||
|
@ -502,6 +619,5 @@ CuSuite *get_magic_suite(void)
|
|||
SUITE_ADD_TEST(suite, test_magic_resistance);
|
||||
SUITE_ADD_TEST(suite, test_max_spellpoints);
|
||||
SUITE_ADD_TEST(suite, test_illusioncastle);
|
||||
DISABLE_TEST(suite, test_familiar_mage);
|
||||
return suite;
|
||||
}
|
||||
|
|
|
@ -147,8 +147,7 @@ newfaction *read_newfactions(const char *filename)
|
|||
faction *f;
|
||||
char race[20], email[64], lang[8], password[16];
|
||||
newfaction *nf, **nfi;
|
||||
int bonus = 0, subscription = 0;
|
||||
int alliance = 0;
|
||||
int alliance = 0, subscription = 0;
|
||||
|
||||
if (fgets(buf, sizeof(buf), F) == NULL)
|
||||
break;
|
||||
|
@ -156,8 +155,8 @@ newfaction *read_newfactions(const char *filename)
|
|||
email[0] = '\0';
|
||||
password[0] = '\0';
|
||||
|
||||
if (sscanf(buf, "%54s %20s %8s %d %d %16s %d", email, race, lang, &bonus,
|
||||
&subscription, password, &alliance) < 3) {
|
||||
if (sscanf(buf, "%54s %20s %8s %16s %d %d", email, race, lang,
|
||||
password, &subscription, &alliance) < 3) {
|
||||
break;
|
||||
}
|
||||
if (email[0] == '#') {
|
||||
|
@ -228,7 +227,6 @@ newfaction *read_newfactions(const char *filename)
|
|||
}
|
||||
}
|
||||
nf->lang = get_locale(lang);
|
||||
nf->bonus = bonus;
|
||||
assert(nf->race && nf->email && nf->lang);
|
||||
nfi = &newfactions;
|
||||
while (*nfi) {
|
||||
|
|
|
@ -24,7 +24,6 @@ extern "C" {
|
|||
char *password;
|
||||
const struct locale *lang;
|
||||
const struct race *race;
|
||||
int bonus;
|
||||
int subscription;
|
||||
bool oldregions;
|
||||
struct alliance *allies;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
+-------------------+ Christian Schlittchen <corwin@amber.kn-bremen.de>
|
||||
| | Enno Rehling <enno@eressea.de>
|
||||
| Eressea PBEM host | Katja Zedel <katze@felidae.kn-bremen.de>
|
||||
|
@ -14,7 +14,7 @@
|
|||
#include <kernel/config.h>
|
||||
#include "xmas.h"
|
||||
|
||||
/* kernel includes */
|
||||
/* kernel includes */
|
||||
#include <kernel/building.h>
|
||||
#include <kernel/faction.h>
|
||||
#include <kernel/item.h>
|
||||
|
@ -50,10 +50,7 @@ static void xmasgate_write(const trigger * t, struct storage *store)
|
|||
|
||||
static int xmasgate_read(trigger * t, struct gamedata *data)
|
||||
{
|
||||
int bc =
|
||||
read_reference(&t->data.v, data, read_building_reference,
|
||||
resolve_building);
|
||||
if (bc == 0 && !t->data.v) {
|
||||
if (read_building_reference(data, (building **)&t->data.v, NULL) <= 0) {
|
||||
return AT_READ_FAIL;
|
||||
}
|
||||
return AT_READ_OK;
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
#include <kernel/pool.h>
|
||||
#include <kernel/race.h>
|
||||
#include <kernel/region.h>
|
||||
#include <kernel/ship.h>
|
||||
#include <kernel/terrain.h>
|
||||
#include <kernel/terrainid.h>
|
||||
#include <kernel/unit.h>
|
||||
|
@ -191,6 +192,7 @@ void monsters_desert(struct faction *monsters)
|
|||
|
||||
int monster_attacks(unit * monster, bool rich_only)
|
||||
{
|
||||
const race *rc_serpent = get_race(RC_SEASERPENT);
|
||||
if (monster->status < ST_AVOID) {
|
||||
region *r = monster->region;
|
||||
unit *u2;
|
||||
|
@ -199,6 +201,12 @@ int monster_attacks(unit * monster, bool rich_only)
|
|||
for (u2 = r->units; u2; u2 = u2->next) {
|
||||
if (u2->faction != monster->faction && cansee(monster->faction, r, u2, 0) && !in_safe_building(u2, monster)) {
|
||||
int m = get_money(u2);
|
||||
if (u_race(monster) == rc_serpent) {
|
||||
/* attack bigger ships only */
|
||||
if (!u2->ship || u2->ship->type->cargo <= 50000) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!rich_only || m > 0) {
|
||||
order *ord = monster_attack(monster, u2);
|
||||
if (ord) {
|
||||
|
@ -604,7 +612,7 @@ static void recruit_dracoids(unit * dragon, int size)
|
|||
|
||||
name_unit(un);
|
||||
change_money(dragon, -un->number * 50);
|
||||
equip_unit(un, get_equipment("recruited_dracoid"));
|
||||
equip_unit(un, get_equipment("new_dracoid"));
|
||||
|
||||
setstatus(un, ST_FIGHT);
|
||||
for (weapon = un->items; weapon; weapon = weapon->next) {
|
||||
|
@ -855,7 +863,7 @@ static int nrand(int start, int sub)
|
|||
unit *spawn_seaserpent(region *r, faction *f) {
|
||||
unit *u = create_unit(r, f, 1, get_race(RC_SEASERPENT), 0, NULL, NULL);
|
||||
fset(u, UFL_ISNEW | UFL_MOVED);
|
||||
equip_unit(u, get_equipment("monster_seaserpent"));
|
||||
equip_unit(u, get_equipment("seed_seaserpent"));
|
||||
return u;
|
||||
}
|
||||
|
||||
|
@ -886,7 +894,7 @@ void spawn_dragons(void)
|
|||
u = create_unit(r, monsters, nrand(30, 20) + 1, get_race(RC_DRAGON), 0, NULL, NULL);
|
||||
}
|
||||
fset(u, UFL_ISNEW | UFL_MOVED);
|
||||
equip_unit(u, get_equipment("monster_dragon"));
|
||||
equip_unit(u, get_equipment("seed_dragon"));
|
||||
|
||||
log_debug("spawning %d %s in %s.\n", u->number,
|
||||
LOC(default_locale,
|
||||
|
@ -1124,7 +1132,7 @@ faction *get_or_create_monsters(void)
|
|||
if (!f) {
|
||||
const race *rc = rc_get_or_create("dragon");
|
||||
const char *email = config_get("monster.email");
|
||||
f = addfaction(email ? email : "noreply@eressea.de", NULL, rc, default_locale, 0);
|
||||
f = addfaction(email ? email : NULL, NULL, rc, default_locale, 0);
|
||||
renumber_faction(f, MONSTER_ID);
|
||||
faction_setname(f, "Monster");
|
||||
fset(f, FFL_NPC | FFL_NOIDLEOUT);
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#include <kernel/order.h>
|
||||
#include <kernel/race.h>
|
||||
#include <kernel/region.h>
|
||||
#include <kernel/region.h>
|
||||
#include <kernel/ship.h>
|
||||
#include <kernel/terrain.h>
|
||||
#include <kernel/unit.h>
|
||||
|
||||
|
@ -41,43 +43,43 @@ static order *find_order(const char *expected, const unit *unit)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void create_monsters(faction **player, faction **monsters, unit **u, unit **m) {
|
||||
static void create_monsters(unit **up, unit **um) {
|
||||
race* rc;
|
||||
region *r;
|
||||
faction *fp, *fm;
|
||||
|
||||
test_cleanup();
|
||||
|
||||
test_create_horse();
|
||||
default_locale = test_create_locale();
|
||||
*player = test_create_faction(NULL);
|
||||
*monsters = get_or_create_monsters();
|
||||
assert(rc_find((*monsters)->race->_name));
|
||||
rc = rc_get_or_create((*monsters)->race->_name);
|
||||
fp = test_create_faction(NULL);
|
||||
fm = get_or_create_monsters();
|
||||
assert(rc_find(fm->race->_name));
|
||||
rc = rc_get_or_create(fm->race->_name);
|
||||
fset(rc, RCF_UNARMEDGUARD|RCF_NPC|RCF_DRAGON);
|
||||
fset(*monsters, FFL_NOIDLEOUT);
|
||||
assert(fval(*monsters, FFL_NPC) && fval((*monsters)->race, RCF_UNARMEDGUARD) && fval((*monsters)->race, RCF_NPC) && fval(*monsters, FFL_NOIDLEOUT));
|
||||
fset(fm, FFL_NOIDLEOUT);
|
||||
assert(fval(fm, FFL_NPC) && fval(fm->race, RCF_UNARMEDGUARD) && fval(fm->race, RCF_NPC) && fval(fm, FFL_NOIDLEOUT));
|
||||
|
||||
test_create_region(-1, 0, test_create_terrain("ocean", SEA_REGION | SWIM_INTO | FLY_INTO));
|
||||
test_create_region(1, 0, 0);
|
||||
r = test_create_region(0, 0, 0);
|
||||
|
||||
*u = test_create_unit(*player, r);
|
||||
unit_setid(*u, 1);
|
||||
*m = test_create_unit(*monsters, r);
|
||||
unit_setstatus(*m, ST_FIGHT);
|
||||
*up = test_create_unit(fp, r);
|
||||
unit_setid(*up, 1);
|
||||
*um = test_create_unit(fm, r);
|
||||
unit_setstatus(*um, ST_FIGHT);
|
||||
}
|
||||
|
||||
static void test_monsters_attack(CuTest * tc)
|
||||
{
|
||||
faction *f, *f2;
|
||||
unit *u, *m;
|
||||
|
||||
create_monsters(&f, &f2, &u, &m);
|
||||
create_monsters(&u, &m);
|
||||
setguard(m, true);
|
||||
|
||||
config_set("rules.monsters.attack_chance", "1");
|
||||
|
||||
plan_monsters(f2);
|
||||
plan_monsters(m->faction);
|
||||
|
||||
CuAssertPtrNotNull(tc, find_order("attack 1", m));
|
||||
test_cleanup();
|
||||
|
@ -85,11 +87,10 @@ static void test_monsters_attack(CuTest * tc)
|
|||
|
||||
static void test_monsters_attack_ocean(CuTest * tc)
|
||||
{
|
||||
faction *f, *f2;
|
||||
region *r;
|
||||
unit *u, *m;
|
||||
|
||||
create_monsters(&f, &f2, &u, &m);
|
||||
create_monsters(&u, &m);
|
||||
r = findregion(-1, 0); /* ocean */
|
||||
u = test_create_unit(u->faction, r);
|
||||
unit_setid(u, 2);
|
||||
|
@ -98,7 +99,7 @@ static void test_monsters_attack_ocean(CuTest * tc)
|
|||
|
||||
config_set("rules.monsters.attack_chance", "1");
|
||||
|
||||
plan_monsters(f2);
|
||||
plan_monsters(m->faction);
|
||||
|
||||
CuAssertPtrNotNull(tc, find_order("attack 2", m));
|
||||
test_cleanup();
|
||||
|
@ -106,10 +107,9 @@ static void test_monsters_attack_ocean(CuTest * tc)
|
|||
|
||||
static void test_monsters_waiting(CuTest * tc)
|
||||
{
|
||||
faction *f, *f2;
|
||||
unit *u, *m;
|
||||
|
||||
create_monsters(&f, &f2, &u, &m);
|
||||
create_monsters(&u, &m);
|
||||
setguard(m, true);
|
||||
fset(m, UFL_ISNEW);
|
||||
monster_attacks(m, false);
|
||||
|
@ -119,14 +119,16 @@ static void test_monsters_waiting(CuTest * tc)
|
|||
|
||||
static void test_seaserpent_piracy(CuTest * tc)
|
||||
{
|
||||
faction *f, *f2;
|
||||
region *r;
|
||||
unit *u, *m;
|
||||
race *rc;
|
||||
ship_type * stype;
|
||||
|
||||
create_monsters(&f, &f2, &u, &m);
|
||||
create_monsters(&u, &m);
|
||||
stype = test_create_shiptype("yacht");
|
||||
r = findregion(-1, 0); /* ocean */
|
||||
u = test_create_unit(u->faction, r);
|
||||
u->ship = test_create_ship(r, stype);
|
||||
unit_setid(u, 2);
|
||||
m = test_create_unit(m->faction, r);
|
||||
u_setrace(m, rc = test_create_race("seaserpent"));
|
||||
|
@ -136,25 +138,28 @@ static void test_seaserpent_piracy(CuTest * tc)
|
|||
|
||||
config_set("rules.monsters.attack_chance", "1");
|
||||
|
||||
plan_monsters(f2);
|
||||
stype->cargo = 50000;
|
||||
plan_monsters(m->faction);
|
||||
CuAssertPtrNotNull(tc, find_order("piracy", m));
|
||||
CuAssertPtrEquals(tc, NULL, find_order("attack 2", m));
|
||||
stype->cargo = 50001;
|
||||
plan_monsters(m->faction);
|
||||
CuAssertPtrNotNull(tc, find_order("attack 2", m));
|
||||
test_cleanup();
|
||||
}
|
||||
|
||||
static void test_monsters_attack_not(CuTest * tc)
|
||||
{
|
||||
faction *f, *f2;
|
||||
unit *u, *m;
|
||||
|
||||
create_monsters(&f, &f2, &u, &m);
|
||||
create_monsters(&u, &m);
|
||||
|
||||
setguard(m, true);
|
||||
setguard(u, true);
|
||||
|
||||
config_set("rules.monsters.attack_chance", "0");
|
||||
|
||||
plan_monsters(f2);
|
||||
plan_monsters(m->faction);
|
||||
|
||||
CuAssertPtrEquals(tc, 0, find_order("attack 1", m));
|
||||
test_cleanup();
|
||||
|
@ -162,11 +167,10 @@ static void test_monsters_attack_not(CuTest * tc)
|
|||
|
||||
static void test_dragon_attacks_the_rich(CuTest * tc)
|
||||
{
|
||||
faction *f, *f2;
|
||||
unit *u, *m;
|
||||
const item_type *i_silver;
|
||||
|
||||
create_monsters(&f, &f2, &u, &m);
|
||||
create_monsters(&u, &m);
|
||||
init_resources();
|
||||
|
||||
setguard(m, true);
|
||||
|
@ -180,8 +184,7 @@ static void test_dragon_attacks_the_rich(CuTest * tc)
|
|||
|
||||
config_set("rules.monsters.attack_chance", "0.00001");
|
||||
|
||||
plan_monsters(f2);
|
||||
|
||||
plan_monsters(m->faction);
|
||||
CuAssertPtrNotNull(tc, find_order("attack 1", m));
|
||||
CuAssertPtrNotNull(tc, find_order("loot", m));
|
||||
test_cleanup();
|
||||
|
@ -191,12 +194,11 @@ extern void random_growl(const unit *u, region *tr, int rand);
|
|||
|
||||
static void test_dragon_moves(CuTest * tc)
|
||||
{
|
||||
faction *f, *f2;
|
||||
region *r;
|
||||
unit *u, *m;
|
||||
struct message *msg;
|
||||
|
||||
create_monsters(&f, &f2, &u, &m);
|
||||
create_monsters(&u, &m);
|
||||
rsetmoney(findregion(1, 0), 1000);
|
||||
r = findregion(0, 0); /* plain */
|
||||
rsetpeasants(r, 0);
|
||||
|
@ -204,8 +206,8 @@ static void test_dragon_moves(CuTest * tc)
|
|||
|
||||
set_level(m, SK_WEAPONLESS, 10);
|
||||
config_set("rules.monsters.attack_chance", ".0");
|
||||
plan_monsters(f2);
|
||||
|
||||
plan_monsters(m->faction);
|
||||
CuAssertPtrNotNull(tc, find_order("move east", m));
|
||||
|
||||
mt_register(mt_new_va("dragon_growl", "dragon:unit", "number:int", "target:region", "growl:string", 0));
|
||||
|
@ -224,11 +226,10 @@ static void test_dragon_moves(CuTest * tc)
|
|||
|
||||
static void test_monsters_learn_exp(CuTest * tc)
|
||||
{
|
||||
faction *f, *f2;
|
||||
unit *u, *m;
|
||||
skill* sk;
|
||||
|
||||
create_monsters(&f, &f2, &u, &m);
|
||||
create_monsters(&u, &m);
|
||||
config_set("study.produceexp", "30");
|
||||
|
||||
u_setrace(u, u_race(m));
|
||||
|
|
80
src/move.c
80
src/move.c
|
@ -89,14 +89,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
#include <limits.h>
|
||||
#include <float.h>
|
||||
|
||||
/* Bewegungsweiten: */
|
||||
#define BP_WALKING 4
|
||||
#define BP_RIDING 6
|
||||
#define BP_UNICORN 9
|
||||
#define BP_DRAGON 4
|
||||
#define BP_NORMAL 3
|
||||
#define BP_ROAD 2
|
||||
|
||||
int *storms;
|
||||
|
||||
typedef struct traveldir {
|
||||
|
@ -265,7 +257,7 @@ get_transporters(const item * itm, int *p_animals, int *p_acap, int *p_vehicles,
|
|||
*p_acap = acap;
|
||||
}
|
||||
|
||||
static int ridingcapacity(unit * u)
|
||||
static int ridingcapacity(const unit * u)
|
||||
{
|
||||
int vehicles = 0, vcap = 0;
|
||||
int animals = 0, acap = 0;
|
||||
|
@ -433,7 +425,7 @@ bool canswim(unit * u)
|
|||
return false;
|
||||
}
|
||||
|
||||
static int canride(unit * u)
|
||||
static int walk_mode(const unit * u)
|
||||
{
|
||||
int horses = 0, maxhorses, unicorns = 0, maxunicorns;
|
||||
int skill = effskill(u, SK_RIDING, 0);
|
||||
|
@ -460,17 +452,17 @@ static int canride(unit * u)
|
|||
if (!(u_race(u)->flags & RCF_HORSE)
|
||||
&& ((horses == 0 && unicorns == 0)
|
||||
|| horses > maxhorses || unicorns > maxunicorns)) {
|
||||
return 0;
|
||||
return BP_WALKING;
|
||||
}
|
||||
|
||||
if (ridingcapacity(u) - eff_weight(u) >= 0) {
|
||||
if (horses == 0 && unicorns >= u->number && !(u_race(u)->flags & RCF_HORSE)) {
|
||||
return 2;
|
||||
return BP_UNICORN;
|
||||
}
|
||||
return 1;
|
||||
return BP_RIDING;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return BP_WALKING;
|
||||
}
|
||||
|
||||
static bool cansail(const region * r, ship * sh)
|
||||
|
@ -1399,9 +1391,9 @@ static void make_route(unit * u, order * ord, region_list ** routep)
|
|||
* Normalerweise verliert man 3 BP pro Region, bei Straßen nur 2 BP.
|
||||
* Außerdem: Wenn Einheit transportiert, nur halbe BP
|
||||
*/
|
||||
static int movement_speed(unit * u)
|
||||
int movement_speed(const unit * u)
|
||||
{
|
||||
int mp = BP_WALKING;
|
||||
int mp = 0;
|
||||
const race *rc = u_race(u);
|
||||
double dk = rc->speed;
|
||||
assert(u->number);
|
||||
|
@ -1415,6 +1407,10 @@ static int movement_speed(unit * u)
|
|||
mp = BP_DRAGON;
|
||||
break;
|
||||
default:
|
||||
mp = walk_mode(u);
|
||||
if (mp>=BP_RIDING) {
|
||||
dk = 1.0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1426,38 +1422,22 @@ static int movement_speed(unit * u)
|
|||
}
|
||||
}
|
||||
|
||||
switch (canride(u)) {
|
||||
case 1: /* Pferd */
|
||||
mp = BP_RIDING;
|
||||
break;
|
||||
/* unicorn in inventory */
|
||||
if (u->number <= i_get(u->items, it_find("fairyboot"))) {
|
||||
mp *= 2;
|
||||
}
|
||||
|
||||
case 2: /* Einhorn */
|
||||
mp = BP_UNICORN;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Siebenmeilentee */
|
||||
if (get_effect(u, oldpotiontype[P_FAST]) >= u->number) {
|
||||
mp *= 2;
|
||||
change_effect(u, oldpotiontype[P_FAST], -u->number);
|
||||
}
|
||||
|
||||
/* unicorn in inventory */
|
||||
if (u->number <= i_get(u->items, it_find("fairyboot"))) {
|
||||
mp *= 2;
|
||||
}
|
||||
|
||||
/* Im Astralraum sind Tyb und Ill-Magier doppelt so schnell.
|
||||
* Nicht kumulativ mit anderen Beschleunigungen! */
|
||||
if (mp * dk <= BP_WALKING * u_race(u)->speed && is_astral(u->region)
|
||||
&& is_mage(u)) {
|
||||
sc_mage *mage = get_mage(u);
|
||||
if (mage->magietyp == M_TYBIED || mage->magietyp == M_ILLAUN) {
|
||||
/* Im Astralraum sind Tyb und Ill-Magier doppelt so schnell.
|
||||
* Nicht kumulativ mit anderen Beschleunigungen! */
|
||||
if (mp * dk <= BP_WALKING * u_race(u)->speed && is_astral(u->region)) {
|
||||
sc_mage *mage = get_mage(u);
|
||||
if (mage && (mage->magietyp == M_TYBIED || mage->magietyp == M_ILLAUN)) {
|
||||
if (has_skill(u, SK_MAGIC)) {
|
||||
mp *= 2;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return (int)(dk * mp);
|
||||
}
|
||||
|
||||
|
@ -1631,7 +1611,7 @@ static const region_list *travel_route(unit * u,
|
|||
if (mode == TRAVEL_RUNNING) {
|
||||
walkmode = 0;
|
||||
}
|
||||
if (canride(u)) {
|
||||
else if (walk_mode(u) >= BP_RIDING) {
|
||||
walkmode = 1;
|
||||
produceexp(u, SK_RIDING, u->number);
|
||||
}
|
||||
|
@ -2044,7 +2024,7 @@ static const region_list *travel_i(unit * u, const region_list * route_begin,
|
|||
const region_list * route_end, order * ord, int mode, follower ** followers)
|
||||
{
|
||||
region *r = u->region;
|
||||
|
||||
int mp;
|
||||
if (u->building && !can_leave(u)) {
|
||||
cmistake(u, u->thisorder, 150, MSG_MOVE);
|
||||
return route_begin;
|
||||
|
@ -2060,7 +2040,15 @@ static const region_list *travel_i(unit * u, const region_list * route_begin,
|
|||
cmistake(u, ord, 42, MSG_MOVE);
|
||||
return route_begin;
|
||||
}
|
||||
route_end = cap_route(r, route_begin, route_end, movement_speed(u));
|
||||
|
||||
mp = movement_speed(u);
|
||||
/* Siebenmeilentee */
|
||||
if (get_effect(u, oldpotiontype[P_FAST]) >= u->number) {
|
||||
mp *= 2;
|
||||
change_effect(u, oldpotiontype[P_FAST], -u->number);
|
||||
}
|
||||
|
||||
route_end = cap_route(r, route_begin, route_end, mp);
|
||||
|
||||
route_end = travel_route(u, route_begin, route_end, ord, mode);
|
||||
if (u->flags&UFL_FOLLOWED) {
|
||||
|
|
|
@ -36,6 +36,14 @@ extern "C" {
|
|||
extern struct attrib_type at_shiptrail;
|
||||
extern int *storms;
|
||||
|
||||
/* Bewegungsweiten: */
|
||||
#define BP_WALKING 4
|
||||
#define BP_RIDING 6
|
||||
#define BP_UNICORN 9
|
||||
#define BP_DRAGON 4
|
||||
#define BP_NORMAL 3
|
||||
#define BP_ROAD 2
|
||||
|
||||
/* die Zahlen sind genau äquivalent zu den race Flags */
|
||||
#define MV_CANNOTMOVE (1<<5)
|
||||
#define MV_FLY (1<<7) /* kann fliegen */
|
||||
|
@ -70,6 +78,7 @@ extern "C" {
|
|||
struct ship *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);
|
||||
void follow_unit(struct unit *u);
|
||||
struct unit *owner_buildingtyp(const struct region *r,
|
||||
const struct building_type *bt);
|
||||
|
|
|
@ -522,9 +522,33 @@ static void test_ship_leave_trail(CuTest *tc) {
|
|||
test_cleanup();
|
||||
}
|
||||
|
||||
static void test_movement_speed(CuTest *tc) {
|
||||
unit * u;
|
||||
race * rc;
|
||||
const struct item_type *it_horse;
|
||||
|
||||
test_setup();
|
||||
it_horse = test_create_horse();
|
||||
rc = test_create_race(NULL);
|
||||
u = test_create_unit(test_create_faction(rc), test_create_region(0, 0, NULL));
|
||||
|
||||
rc->speed = 1.0;
|
||||
CuAssertIntEquals(tc, BP_WALKING, movement_speed(u));
|
||||
|
||||
rc->speed = 2.0;
|
||||
CuAssertIntEquals(tc, 2 * BP_WALKING, movement_speed(u));
|
||||
|
||||
set_level(u, SK_RIDING, 1);
|
||||
i_change(&u->items, it_horse, 1);
|
||||
CuAssertIntEquals(tc, BP_RIDING, movement_speed(u));
|
||||
|
||||
test_cleanup();
|
||||
}
|
||||
|
||||
CuSuite *get_move_suite(void)
|
||||
{
|
||||
CuSuite *suite = CuSuiteNew();
|
||||
SUITE_ADD_TEST(suite, test_movement_speed);
|
||||
SUITE_ADD_TEST(suite, test_walkingcapacity);
|
||||
SUITE_ADD_TEST(suite, test_ship_not_allowed_in_coast);
|
||||
SUITE_ADD_TEST(suite, test_ship_leave_trail);
|
||||
|
|
245
src/orderfile.c
Normal file
245
src/orderfile.c
Normal file
|
@ -0,0 +1,245 @@
|
|||
#include <platform.h>
|
||||
#include <kernel/config.h>
|
||||
#include "orderfile.h"
|
||||
|
||||
#include <kernel/faction.h>
|
||||
#include <kernel/unit.h>
|
||||
#include <kernel/order.h>
|
||||
#include <kernel/messages.h>
|
||||
|
||||
#include <util/base36.h>
|
||||
#include <util/message.h>
|
||||
#include <util/language.h>
|
||||
#include <util/log.h>
|
||||
#include <util/filereader.h>
|
||||
#include <util/parser.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
static unit *unitorders(input *in, faction *f)
|
||||
{
|
||||
int i;
|
||||
unit *u;
|
||||
|
||||
if (!f)
|
||||
return NULL;
|
||||
|
||||
i = getid();
|
||||
u = findunitg(i, NULL);
|
||||
|
||||
if (u && u->faction == f) {
|
||||
order **ordp;
|
||||
|
||||
if (!fval(u, UFL_ORDERS)) {
|
||||
/* alle wiederholbaren, langen befehle werden gesichert: */
|
||||
fset(u, UFL_ORDERS);
|
||||
u->old_orders = u->orders;
|
||||
ordp = &u->old_orders;
|
||||
while (*ordp) {
|
||||
order *ord = *ordp;
|
||||
keyword_t kwd = getkeyword(ord);
|
||||
if (!is_repeated(kwd)) {
|
||||
*ordp = ord->next;
|
||||
ord->next = NULL;
|
||||
free_order(ord);
|
||||
}
|
||||
else {
|
||||
ordp = &ord->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
free_orders(&u->orders);
|
||||
}
|
||||
u->orders = 0;
|
||||
|
||||
ordp = &u->orders;
|
||||
|
||||
for (;;) {
|
||||
const char *s;
|
||||
/* Erst wenn wir sicher sind, dass kein Befehl
|
||||
* eingegeben wurde, checken wir, ob nun eine neue
|
||||
* Einheit oder ein neuer Spieler drankommt */
|
||||
|
||||
s = in->getbuf(in->data);
|
||||
if (s == NULL)
|
||||
break;
|
||||
|
||||
if (s[0]) {
|
||||
if (s[0] != '@') {
|
||||
char token[64];
|
||||
const char *stok = s;
|
||||
stok = parse_token(&stok, token, sizeof(token));
|
||||
|
||||
if (stok) {
|
||||
bool quit = false;
|
||||
param_t param = findparam(stok, u->faction->locale);
|
||||
switch (param) {
|
||||
case P_UNIT:
|
||||
case P_REGION:
|
||||
quit = true;
|
||||
break;
|
||||
case P_FACTION:
|
||||
case P_NEXT:
|
||||
case P_GAMENAME:
|
||||
/* these terminate the orders, so we apply extra checking */
|
||||
if (strlen(stok) >= 3) {
|
||||
quit = true;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
quit = false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (quit) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Nun wird der Befehl erzeut und eingehängt */
|
||||
*ordp = parse_order(s, u->faction->locale);
|
||||
if (*ordp) {
|
||||
ordp = &(*ordp)->next;
|
||||
}
|
||||
else {
|
||||
ADDMSG(&f->msgs, msg_message("parse_error", "unit command", u, s));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
return u;
|
||||
}
|
||||
|
||||
static faction *factionorders(void)
|
||||
{
|
||||
faction *f = NULL;
|
||||
int fid = getid();
|
||||
|
||||
f = findfaction(fid);
|
||||
|
||||
if (f != NULL && !fval(f, FFL_NPC)) {
|
||||
char token[128];
|
||||
const char *pass = gettoken(token, sizeof(token));
|
||||
|
||||
if (!checkpasswd(f, (const char *)pass)) {
|
||||
log_debug("Invalid password for faction %s", itoa36(fid));
|
||||
ADDMSG(&f->msgs, msg_message("wrongpasswd", "password", pass));
|
||||
return 0;
|
||||
}
|
||||
/* Die Partei hat sich zumindest gemeldet, so dass sie noch
|
||||
* nicht als untätig gilt */
|
||||
f->lastorders = turn;
|
||||
|
||||
}
|
||||
else {
|
||||
log_debug("orders for invalid faction %s", itoa36(fid));
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
int read_orders(input *in)
|
||||
{
|
||||
const char *b;
|
||||
int nfactions = 0;
|
||||
struct faction *f = NULL;
|
||||
|
||||
/* TODO: recognize UTF8 BOM */
|
||||
b = in->getbuf(in->data);
|
||||
|
||||
/* Auffinden der ersten Partei, und danach abarbeiten bis zur letzten
|
||||
* Partei */
|
||||
|
||||
while (b) {
|
||||
char token[128];
|
||||
const struct locale *lang = f ? f->locale : default_locale;
|
||||
param_t p;
|
||||
const char *s;
|
||||
init_tokens_str(b);
|
||||
s = gettoken(token, sizeof(token));
|
||||
p = findparam_block(s, lang, true);
|
||||
switch (p) {
|
||||
case P_GAMENAME:
|
||||
case P_FACTION:
|
||||
f = factionorders();
|
||||
if (f) {
|
||||
++nfactions;
|
||||
}
|
||||
|
||||
b = in->getbuf(in->data);
|
||||
break;
|
||||
|
||||
/* in factionorders wird nur eine zeile gelesen:
|
||||
* diejenige mit dem passwort. Die befehle der units
|
||||
* werden geloescht, und die Partei wird als aktiv
|
||||
* vermerkt. */
|
||||
|
||||
case P_UNIT:
|
||||
if (!f || !unitorders(in, f)) {
|
||||
do {
|
||||
b = in->getbuf(in->data);
|
||||
if (!b) {
|
||||
break;
|
||||
}
|
||||
init_tokens_str(b);
|
||||
s = gettoken(token, sizeof(token));
|
||||
p = (s && s[0] != '@') ? findparam(s, lang) : NOPARAM;
|
||||
} while ((p != P_UNIT || !f) && p != P_FACTION && p != P_NEXT
|
||||
&& p != P_GAMENAME);
|
||||
}
|
||||
break;
|
||||
|
||||
/* Falls in unitorders() abgebrochen wird, steht dort entweder eine neue
|
||||
* Partei, eine neue Einheit oder das File-Ende. Das switch() wird erneut
|
||||
* durchlaufen, und die entsprechende Funktion aufgerufen. Man darf buf
|
||||
* auf alle Fälle nicht überschreiben! Bei allen anderen Einträgen hier
|
||||
* muss buf erneut gefüllt werden, da die betreffende Information in nur
|
||||
* einer Zeile steht, und nun die nächste gelesen werden muss. */
|
||||
|
||||
case P_NEXT:
|
||||
f = NULL;
|
||||
b = in->getbuf(in->data);
|
||||
break;
|
||||
|
||||
default:
|
||||
b = in->getbuf(in->data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
log_info("done reading orders for %d factions", nfactions);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char * file_getbuf(void *data)
|
||||
{
|
||||
FILE *F = (FILE *)data;
|
||||
return getbuf(F, ENCODING_UTF8);
|
||||
}
|
||||
|
||||
int readorders(const char *filename)
|
||||
{
|
||||
input in;
|
||||
int result;
|
||||
|
||||
FILE *F = NULL;
|
||||
F = fopen(filename, "r");
|
||||
if (!F) {
|
||||
perror(filename);
|
||||
return -1;
|
||||
}
|
||||
log_info("reading orders from %s", filename);
|
||||
in.getbuf = file_getbuf;
|
||||
in.data = F;
|
||||
result = read_orders(&in);
|
||||
fclose(F);
|
||||
return result;
|
||||
}
|
21
src/orderfile.h
Normal file
21
src/orderfile.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
#ifndef H_ORDERFILE
|
||||
#define H_ORDERFILE
|
||||
|
||||
#include <skill.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct input {
|
||||
const char *(*getbuf)(void *data);
|
||||
void *data;
|
||||
} input;
|
||||
|
||||
int read_orders(struct input *in);
|
||||
int readorders(const char *filename);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
88
src/orderfile.test.c
Normal file
88
src/orderfile.test.c
Normal file
|
@ -0,0 +1,88 @@
|
|||
#include <platform.h>
|
||||
#include <kernel/config.h>
|
||||
|
||||
#include "orderfile.h"
|
||||
|
||||
#include <kernel/faction.h>
|
||||
|
||||
#include <CuTest.h>
|
||||
#include <tests.h>
|
||||
|
||||
static const char *getbuf_null(void *data)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void test_read_orders(CuTest *tc) {
|
||||
input in;
|
||||
test_setup();
|
||||
in.getbuf = getbuf_null;
|
||||
in.data = NULL;
|
||||
CuAssertIntEquals(tc, 0, read_orders(&in));
|
||||
test_cleanup();
|
||||
}
|
||||
|
||||
typedef struct order_list {
|
||||
const char **orders;
|
||||
int next;
|
||||
} order_list;
|
||||
|
||||
static const char *getbuf_list(void *data)
|
||||
{
|
||||
order_list * olist = (order_list *)data;
|
||||
return olist->orders[olist->next++];
|
||||
}
|
||||
|
||||
static void test_faction_password_okay(CuTest *tc) {
|
||||
input in;
|
||||
faction *f;
|
||||
order_list olist;
|
||||
const char *orders[] = { "ERESSEA 1 password", NULL };
|
||||
|
||||
test_setup();
|
||||
f = test_create_faction(NULL);
|
||||
renumber_faction(f, 1);
|
||||
CuAssertIntEquals(tc, 1, f->no);
|
||||
faction_setpassword(f, "password");
|
||||
f->lastorders = turn - 1;
|
||||
olist.orders = orders;
|
||||
olist.next = 0;
|
||||
in.getbuf = getbuf_list;
|
||||
in.data = &olist;
|
||||
CuAssertIntEquals(tc, 0, read_orders(&in));
|
||||
CuAssertIntEquals(tc, 2, olist.next);
|
||||
CuAssertIntEquals(tc, turn, f->lastorders);
|
||||
test_cleanup();
|
||||
}
|
||||
|
||||
static void test_faction_password_bad(CuTest *tc) {
|
||||
input in;
|
||||
faction *f;
|
||||
order_list olist;
|
||||
const char *orders[] = { "ERESSEA 1 password", NULL };
|
||||
|
||||
test_setup();
|
||||
f = test_create_faction(NULL);
|
||||
renumber_faction(f, 1);
|
||||
CuAssertIntEquals(tc, 1, f->no);
|
||||
faction_setpassword(f, "patzword");
|
||||
f->lastorders = turn - 1;
|
||||
olist.orders = orders;
|
||||
olist.next = 0;
|
||||
in.getbuf = getbuf_list;
|
||||
in.data = &olist;
|
||||
CuAssertIntEquals(tc, 0, read_orders(&in));
|
||||
CuAssertIntEquals(tc, 2, olist.next);
|
||||
CuAssertIntEquals(tc, turn - 1, f->lastorders);
|
||||
test_cleanup();
|
||||
}
|
||||
|
||||
CuSuite *get_orderfile_suite(void)
|
||||
{
|
||||
CuSuite *suite = CuSuiteNew();
|
||||
SUITE_ADD_TEST(suite, test_read_orders);
|
||||
SUITE_ADD_TEST(suite, test_faction_password_okay);
|
||||
SUITE_ADD_TEST(suite, test_faction_password_bad);
|
||||
|
||||
return suite;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue