Compare commits

..

No commits in common. "develop" and "2758-smurf" have entirely different histories.

64 changed files with 507 additions and 935 deletions

View file

@ -1,37 +0,0 @@
# This is a basic workflow to help you get started with Actions
name: CI
# Controls when the action will run.
on:
# Triggers the workflow on push or pull request events but only for the master branch
push:
branches: [ master, develop ]
pull_request:
branches: [ master, develop ]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
build:
# The type of runner that the job will run on
runs-on: ubuntu-latest
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v2
- name: Install dependencies
run: sudo apt install libexpat1-dev libtolua-dev libncurses5-dev libsqlite3-dev libiniparser-dev libcjson-dev libbsd-dev cppcheck shellcheck luarocks clang-tools
- name: Run .travis.yml build script
uses: ktomk/run-travis-yml@v1
with:
file: .travis.yml
steps: |
install
script
allow-failure: false

View file

@ -21,4 +21,3 @@ addons:
- luarocks
os:
- linux

View file

@ -23,7 +23,6 @@ Here's how you clone and build the source on Linux or macOS:
git clone --recursive git://github.com/eressea/server.git source
cd source
git submodule update --init
s/cmake-init
s/build
If you got this far and all went well, you have built the server, and

View file

@ -36,7 +36,6 @@
"maketemp": ["MACHE TEMP", "MACHETEMP"],
"move" : "NACH",
"password" : "PASSWORT",
"expel" : "VERTREIBE",
"loot" : ["PLÜNDERE", "PLÜNDERN"],
"recruit": ["REKRUTIERE", "REKRUTIEREN"],
"reserve": ["RESERVIERE", "RESERVIEREN"],

View file

@ -47,11 +47,6 @@ if [ ! -s "$ERESSEA/game-$GAME/data/$TURN.dat" ]; then
echo "server did not create data for turn $TURN in game $GAME"
exit 3
fi
if [ ! -f "express-$TURN.txt" ]; then
if [ -f express.txt ]; then
mv express.txt "express-$TURN.txt"
fi
fi
echo "sending reports for game $GAME, turn $TURN"
"$BIN/compress.sh" "$GAME" "$TURN"
"$BIN/sendreports.sh" "$GAME"

View file

@ -4535,6 +4535,13 @@
<arg name="command" type="order"/>
</type>
</message>
<message name="error125" section="errors">
<type>
<arg name="unit" type="unit"/>
<arg name="region" type="region"/>
<arg name="command" type="order"/>
</type>
</message>
<message name="error84" section="errors">
<type>
<arg name="unit" type="unit"/>
@ -4725,13 +4732,6 @@
<arg name="command" type="order"/>
</type>
</message>
<message name="feedback_not_inside" section="errors">
<type>
<arg name="unit" type="unit"/>
<arg name="region" type="region"/>
<arg name="command" type="order"/>
</type>
</message>
<message name="feedback_unit_not_found" section="errors">
<type>
<arg name="unit" type="unit"/>

View file

@ -5,7 +5,7 @@
<!-- begin main races -->
<race name="template" maintenance="0" magres="100" maxaura="0" regaura="0" weight="0" capacity="1000" speed="10.0" hp="10" damage="1d4" unarmedattack="-2" unarmeddefense="-2" playerrace="yes" fly="yes" swim="yes" walk="yes" shapeshift="yes" giveperson="yes" giveunit="yes" getitem="yes" recruitethereal="yes" recruitunlimited="yes" equipment="yes">
<ai splitsize="10000" moverandom="yes"/>
<ai splitsize="10000" moverandom="yes" learn="yes"/>
<attack type="1" damage="1d4"/>
</race>
<race name="lynx" maxaura="0" regaura="0" weight="500" capacity="540" speed="1.0" hp="20" damage="2d3" unarmedattack="0" unarmeddefense="0" attackmodifier="4" defensemodifier="5" walk="yes" teach="no" getitem="yes">
@ -32,7 +32,7 @@
</race>
<race name="human" maxaura="1" regaura="1" recruitcost="100" maintenance="10" weight="1000" capacity="540" speed="1.0" hp="20" damage="1d5" unarmedattack="-2" unarmeddefense="-2" playerrace="yes" walk="yes" giveperson="yes" giveunit="yes" getitem="yes" equipment="yes">
<ai splitsize="10000" moverandom="yes"/>
<ai splitsize="10000" moverandom="yes" learn="yes"/>
<param name="other_race" value="elf"/>
<skill name="riding" modifier="+1"/>
<skill name="shipcraft" modifier="2"/>
@ -45,7 +45,7 @@
</race>
<race name="orc" studyspeed="-5" magres="-5" maxaura="1" regaura="1" recruitcost="100" maintenance="10" weight="1000" capacity="540" speed="1.0" hp="20" damage="1d5" unarmedattack="-2" unarmeddefense="-2" playerrace="yes" walk="yes" giveperson="yes" giveunit="yes" getitem="yes" equipment="yes">
<ai splitsize="10000" moverandom="yes"/>
<ai splitsize="10000" moverandom="yes" learn="yes"/>
<param name="other_race" value="troll"/>
<skill name="bow" speed="+5"/>
@ -76,7 +76,7 @@
capacity="540" speed="1.0" hp="20" damage="1d5" unarmedattack="-2"
unarmeddefense="-2" playerrace="yes" walk="yes" giveperson="yes"
giveunit="yes" getitem="yes" equipment="yes">
<ai splitsize="10000" moverandom="yes"/>
<ai splitsize="10000" moverandom="yes" learn="yes"/>
<param name="other_race" value="dwarf"/>
<param name="luxury_trade" value="600"/>
<skill name="bow" modifier="-1"/>
@ -102,7 +102,7 @@
<!-- begin secondary races -->
<race name="demon" magres="15" maxaura="1" regaura="1.1" recruitcost="360" maintenance="10" weight="1000" capacity="540" speed="1.0" hp="30" ac="2" damage="1d5" unarmedattack="-2" unarmeddefense="-2" playerrace="yes" walk="yes" giveperson="yes" giveunit="yes" getitem="yes" recruitethereal="yes" equipment="yes">
<ai splitsize="10000" moverandom="yes"/>
<ai splitsize="10000" moverandom="yes" learn="yes"/>
<skill name="cartmaking" modifier="-2"/>
<skill name="forestry" modifier="1"/>
<skill name="melee" modifier="1"/>
@ -125,7 +125,7 @@
speed="1.0" hp="20" damage="1d5" unarmedattack="-2"
unarmeddefense="-2" playerrace="yes" walk="yes" giveperson="yes"
giveunit="yes" getitem="yes" equipment="yes" >
<ai splitsize="10000" moverandom="yes"/>
<ai splitsize="10000" moverandom="yes" learn="yes"/>
<skill name="armorer" modifier="-1"/>
<skill name="bow" modifier="2"/>
<skill name="building" modifier="-1"/>
@ -143,7 +143,7 @@
</race>
<race name="troll" magres="10" maxaura="1" regaura="1" recruitcost="260" maintenance="10" weight="2000" capacity="1080" speed="1.0" hp="20" ac="1" damage="1d5+3" unarmedattack="-2" unarmeddefense="-2" playerrace="yes" walk="yes" giveperson="yes" giveunit="yes" getitem="yes" equipment="yes">
<ai splitsize="10000" moverandom="yes"/>
<ai splitsize="10000" moverandom="yes" learn="yes"/>
<param name="armor.stamina" value="4"/> <!-- +1 natural armor per X levels stamina -->
<skill name="armorer" modifier="2"/>
<skill name="bow" modifier="-2"/>
@ -169,7 +169,7 @@
speed="1.0" hp="20" damage="1d5" unarmedattack="-2"
unarmeddefense="-2" playerrace="yes" walk="yes" giveperson="yes"
giveunit="yes" getitem="yes" equipment="yes">
<ai splitsize="10000" moverandom="yes"/>
<ai splitsize="10000" moverandom="yes" learn="yes"/>
<skill name="armorer" modifier="2"/>
<skill name="bow" modifier="-1"/>
<skill name="building" modifier="2"/>
@ -598,13 +598,13 @@
<attack type="1" damage="1d6"/>
</race>
<race name="braineater" magres="90" maxaura="1.0" regaura="1.0" weight="100" capacity="540" speed="1.0" hp="20" damage="0d0" unarmedattack="0" unarmeddefense="0" attackmodifier="6" defensemodifier="10" fly="yes" walk="yes" teach="no" invinciblenonmagic="yes">
<ai splitsize="500" scarepeasants="yes" killpeasants="yes" moverandom="yes"/>
<ai splitsize="500" scarepeasants="yes" killpeasants="yes" moverandom="yes" learn="yes"/>
<attack type="2" damage="3d15"/>
<attack type="3" damage="1d1"/>
<attack type="4" damage="1d1"/>
</race>
<race name="toad" magres="20" maxaura="1" regaura="1" maintenance="10" weight="100" capacity="540" speed="1.0" hp="10" damage="1d2" unarmedattack="-2" unarmeddefense="-2" playerrace="yes" giveperson="yes" giveunit="yes" getitem="yes" walk="yes" learn="no">
<ai splitsize="1"/>
<ai splitsize="1" learn="yes"/>
<skill name="crossbow" modifier="-10"/>
<skill name="mining" modifier="-10"/>
<skill name="bow" modifier="-10"/>
@ -628,7 +628,7 @@
<attack type="4" damage="1d2"/>
</race>
<race name="smurf" weight="1000" capacity="540" speed="1.0" hp="10" damage="1d2" unarmedattack="-2" unarmeddefense="-2" playerrace="yes" giveperson="yes" giveunit="yes" getitem="yes" walk="yes" learn="no">
<ai splitsize="1"/>
<ai splitsize="1" learn="yes"/>
<skill name="crossbow" modifier="-10"/>
<skill name="mining" modifier="-10"/>
<skill name="bow" modifier="-10"/>
@ -656,13 +656,13 @@
<attack type="4" damage="2d40"/>
</race>
<race name="shadowmaster" cansail="no" cansteal="no" learn="no" magres="75" maxaura="1.0" regaura="2.0" weight="500" capacity="540" speed="1.0" hp="150" ac="4" damage="2d5" unarmedattack="0" unarmeddefense="0" attackmodifier="11" defensemodifier="13" walk="yes" teach="no" desert="yes">
<ai splitsize="50" scarepeasants="yes" killpeasants="yes" moverandom="yes"/>
<ai splitsize="50" scarepeasants="yes" killpeasants="yes" moverandom="yes" learn="yes"/>
<attack type="4" damage="2d4"/>
<attack type="2" damage="2d30"/>
<attack type="3" damage="1d2"/>
</race>
<race name="shadowdemon" cansail="no" cansteal="no" learn="no" magres="75" maxaura="1.0" regaura="1.0" weight="500" capacity="540" speed="1.0" hp="50" ac="3" damage="2d4" unarmedattack="0" unarmeddefense="0" attackmodifier="8" defensemodifier="11" walk="yes" teach="no" desert="yes" recruitethereal="yes">
<ai splitsize="1000" scarepeasants="yes" killpeasants="yes" moverandom="yes"/>
<ai splitsize="1000" scarepeasants="yes" killpeasants="yes" moverandom="yes" learn="yes"/>
<attack type="4" damage="2d3"/>
<attack type="3" damage="1d1"/>
</race>
@ -684,14 +684,14 @@
</race>
<race name="dracoid" maxaura="1.0" regaura="1.0" weight="1000" capacity="540" speed="1.0" hp="24" damage="1d5" unarmedattack="-2" unarmeddefense="-2" walk="yes" teach="no" giveperson="yes" getitem="yes" equipment="yes">
<ai splitsize="10000" moverandom="yes"/>
<ai splitsize="10000" moverandom="yes" learn="yes"/>
<attack type="4" damage="1d6"/>
<attack type="4" damage="1d6"/>
<attack type="1" damage="1d5"/>
</race>
<race name="ent" magres="25" maxaura="1.0" regaura="0.5" weight="5000" capacity="2500" speed="1.0" hp="50" ac="4" damage="2d4+12" unarmedattack="0" unarmeddefense="0" attackmodifier="9" defensemodifier="7" walk="yes" teach="no">
<ai splitsize="1000" moverandom="yes" scarepeasants="yes"/>
<ai splitsize="1000" moverandom="yes" learn="yes" scarepeasants="yes"/>
<attack type="4" damage="2d12"/>
<attack type="4" damage="2d12"/>
</race>
@ -832,7 +832,7 @@
</race>
<race name="seaserpent" magres="50" maxaura="1.0" regaura="1.0" weight="20000" capacity="5000" speed="1.0" hp="600" ac="3" damage="2d15" unarmedattack="0" unarmeddefense="0" attackmodifier="4" defensemodifier="4" swim="yes" teach="no" getitem="yes" resistbash="yes">
<ai splitsize="6" scarepeasants="yes" killpeasants="yes" moverandom="yes" moveattack="yes"/>
<ai splitsize="6" scarepeasants="yes" killpeasants="yes" moverandom="yes" learn="yes" moveattack="yes"/>
<skill name="tactics" modifier="4"/>
<skill name="stealth" modifier="-99"/>
<attack type="4" damage="1d30"/>

View file

@ -12,7 +12,7 @@
</race>
<race name="human" maxaura="1.0" regaura="1.0" recruitcost="75" maintenance="10" weight="1000" capacity="540" speed="1.0" hp="20" damage="1d5" unarmedattack="-2" unarmeddefense="-2" playerrace="yes" walk="yes" giveperson="yes" giveunit="yes" getitem="yes" equipment="yes" migrants="yes">
<ai splitsize="10000" moverandom="yes"/>
<ai splitsize="10000" moverandom="yes" learn="yes"/>
<skill name="trade" modifier="1"/>
<skill name="herbalism" modifier="-1"/>
<skill name="shipcraft" modifier="1"/>
@ -579,13 +579,13 @@
</race>
<race name="braineater" magres="90" maxaura="1.0"
regaura="1.0" weight="100" capacity="540" speed="1.0" hp="20" damage="0d0" unarmedattack="0" unarmeddefense="0" attackmodifier="6" defensemodifier="10" fly="yes" walk="yes" teach="no" invinciblenonmagic="yes">
<ai splitsize="500" scarepeasants="yes" killpeasants="yes" moverandom="yes"/>
<ai splitsize="500" scarepeasants="yes" killpeasants="yes" moverandom="yes" learn="yes"/>
<attack type="2" damage="3d15"/>
<attack type="3" damage="1d1"/>
<attack type="4" damage="1d1"/>
</race>
<race name="toad" magres="20" maxaura="1" regaura="1" maintenance="10" weight="100" capacity="540" speed="1" hp="10" damage="1d2" unarmedattack="-2" unarmeddefense="-2" playerrace="yes" giveperson="yes" giveunit="yes" getitem="yes" walk="yes" learn="no">
<ai splitsize="1"/>
<ai splitsize="1" learn="yes"/>
<skill name="alchemy" modifier="-10"/>
<skill name="crossbow" modifier="-10"/>
<skill name="mining" modifier="-10"/>
@ -617,7 +617,7 @@
<attack type="4" damage="1d2"/>
</race>
<race name="smurf" weight="1000" capacity="540" speed="1" hp="10" damage="1d2" unarmedattack="-2" unarmeddefense="-2" playerrace="yes" giveperson="yes" giveunit="yes" getitem="yes" walk="yes" learn="no">
<ai splitsize="1"/>
<ai splitsize="1" learn="yes"/>
<skill name="alchemy" modifier="-10"/>
<skill name="crossbow" modifier="-10"/>
<skill name="mining" modifier="-10"/>
@ -653,13 +653,13 @@
<attack type="4" damage="2d40"/>
</race>
<race name="shadowmaster" cansail="no" cansteal="no" learn="no" magres="75" maxaura="1.0" regaura="2.0" weight="500" capacity="540" speed="1.0" hp="150" ac="4" damage="2d5" unarmedattack="0" unarmeddefense="0" attackmodifier="11" defensemodifier="13" walk="yes" teach="no" desert="yes">
<ai splitsize="50" scarepeasants="yes" killpeasants="yes" moverandom="yes"/>
<ai splitsize="50" scarepeasants="yes" killpeasants="yes" moverandom="yes" learn="yes"/>
<attack type="4" damage="2d4"/>
<attack type="2" damage="2d30"/>
<attack type="3" damage="1d2"/>
</race>
<race name="shadowdemon" cansail="no" cansteal="no" learn="no" magres="75" maxaura="1.0" regaura="1.0" weight="500" capacity="540" speed="1.0" hp="50" ac="3" damage="2d4" unarmedattack="0" unarmeddefense="0" attackmodifier="8" defensemodifier="11" walk="yes" teach="no" desert="yes" recruitethereal="yes">
<ai splitsize="1000" scarepeasants="yes" killpeasants="yes" moverandom="yes"/>
<ai splitsize="1000" scarepeasants="yes" killpeasants="yes" moverandom="yes" learn="yes"/>
<attack type="4" damage="2d3"/>
<attack type="3" damage="1d1"/>
</race>
@ -680,7 +680,7 @@
<attack type="1" damage="1d4"/>
</race>
<race name="dracoid" maxaura="1.0" regaura="1.0" weight="1000" capacity="540" speed="1.0" hp="24" damage="1d5" unarmedattack="-2" unarmeddefense="-2" walk="yes" teach="no" giveperson="yes" getitem="yes" equipment="yes">
<ai splitsize="10000" moverandom="yes"/>
<ai splitsize="10000" moverandom="yes" learn="yes"/>
<attack type="4" damage="1d6"/>
<attack type="4" damage="1d6"/>
<attack type="1" damage="1d5"/>
@ -693,12 +693,12 @@
<attack type="4" damage="2d40"/>
</race>
<race name="ent" magres="25" maxaura="1.0" regaura="0.5" weight="5000" capacity="2500" speed="1.0" hp="50" ac="4" damage="2d4+12" unarmedattack="0" unarmeddefense="0" attackmodifier="9" defensemodifier="7" walk="yes" teach="no">
<ai splitsize="1000" moverandom="yes" scarepeasants="yes"/>
<ai splitsize="1000" moverandom="yes" learn="yes" scarepeasants="yes"/>
<attack type="4" damage="2d12"/>
<attack type="4" damage="2d12"/>
</race>
<race name="wyrm" magres="90" maxaura="1.0" regaura="3.0" weight="18000" capacity="1000000" speed="1.0" hp="2700" ac="8" damage="2d60" unarmedattack="0" unarmeddefense="0" attackmodifier="10" defensemodifier="10" fly="yes" walk="yes" teach="no" getitem="yes" resistbash="yes" dragon="yes" unarmedguard="yes">
<ai splitsize="1" killpeasants="yes" scarepeasants="yes"/>
<ai splitsize="1" killpeasants="yes" learn="yes" scarepeasants="yes"/>
<skill name="magic" modifier="12"/>
<skill name="tactics" modifier="12"/>
<skill name="perception" modifier="10"/>
@ -708,7 +708,7 @@
<attack type="6" spell="powerful_dragonbreath" level="12" />
</race>
<race name="dragon" magres="70" maxaura="1.0" regaura="2.0" weight="10000" capacity="1000000" speed="1.500000" hp="900" ac="6" damage="2d30" unarmedattack="0" unarmeddefense="0" attackmodifier="7" defensemodifier="7" fly="yes" walk="yes" teach="no" getitem="yes" resistbash="yes" unarmedguard="yes" dragon="yes">
<ai splitsize="2" killpeasants="yes" scarepeasants="yes"/>
<ai splitsize="2" killpeasants="yes" learn="yes" scarepeasants="yes"/>
<skill name="magic" modifier="8"/>
<skill name="tactics" modifier="8"/>
<skill name="perception" modifier="5"/>
@ -718,7 +718,7 @@
<attack type="6" spell="icy_dragonbreath" level="6" />
</race>
<race name="youngdragon" magres="50" maxaura="1.0" regaura="1.0" weight="20000" capacity="10000" speed="1.0" hp="300" ac="4" damage="2d15" unarmedattack="0" unarmeddefense="0" attackmodifier="4" defensemodifier="4" fly="yes" walk="yes" teach="no" getitem="yes" resistbash="yes" unarmedguard="yes" dragon="yes">
<ai splitsize="6" killpeasants="yes" scarepeasants="yes"/>
<ai splitsize="6" killpeasants="yes" learn="yes" scarepeasants="yes"/>
<skill name="magic" modifier="4"/>
<skill name="tactics" modifier="4"/>
<skill name="stealth" modifier="2"/>
@ -734,7 +734,7 @@
<attack type="5"/>
</race>
<race name="aquarian" maxaura="1" regaura="1" recruitcost="80" maintenance="10" weight="1000" capacity="540" speed="1" hp="20" damage="1d5" unarmedattack="-2" unarmeddefense="-2" shipspeed="yes" playerrace="yes" coastal="yes" walk="yes" giveperson="yes" giveunit="yes" getitem="yes" equipment="yes">
<ai splitsize="10000" moverandom="yes"/>
<ai splitsize="10000" moverandom="yes" learn="yes"/>
<skill name="mining" modifier="-2"/>
<skill name="building" modifier="-1"/>
<skill name="trade" modifier="2"/>
@ -752,7 +752,7 @@
<familiar race="kraken"/>
</race>
<race name="cat" maxaura="1" regaura="1" recruitcost="90" maintenance="10" weight="1000" capacity="540" speed="1" hp="20" damage="1d5" unarmedattack="-2" unarmeddefense="-2" defensemodifier="1" playerrace="yes" walk="yes" giveperson="yes" giveunit="yes" getitem="yes" equipment="yes">
<ai splitsize="10000" moverandom="yes"/>
<ai splitsize="10000" moverandom="yes" learn="yes"/>
<skill name="alchemy" modifier="-1"/>
<skill name="mining" modifier="-2"/>
<skill name="building" modifier="-1"/>
@ -777,7 +777,7 @@
<familiar race="hellcat"/>
</race>
<race name="halfling" magres="5" maxaura="1" regaura="1" recruitcost="80" maintenance="10" weight="1000" capacity="540" speed="1" hp="18" damage="1d5" unarmedattack="-2" unarmeddefense="-2" playerrace="yes" walk="yes" giveperson="yes" giveunit="yes" getitem="yes" equipment="yes">
<ai splitsize="10000" moverandom="yes"/>
<ai splitsize="10000" moverandom="yes" learn="yes"/>
<param name="hunger_damage" value="1d10+7"/>
<skill name="crossbow" modifier="1"/>
<skill name="mining" modifier="1"/>
@ -809,7 +809,7 @@
<familiar race="rat"/>
</race>
<race name="insect" magres="5" maxaura="1" regaura="1" recruitcost="80" maintenance="10" weight="1000" capacity="540" speed="1" hp="24" ac="2" damage="1d5" unarmedattack="-2" unarmeddefense="-2" playerrace="yes" walk="yes" giveperson="yes" giveunit="yes" getitem="yes" equipment="yes">
<ai splitsize="10000" moverandom="yes"/>
<ai splitsize="10000" moverandom="yes" learn="yes"/>
<skill name="crossbow" modifier="1"/>
<skill name="mining" modifier="1"/>
<skill name="bow" modifier="-2"/>
@ -840,7 +840,7 @@
maintenance="10" weight="1000" capacity="540" speed="1" hp="50" ac="2" damage="1d5"
unarmedattack="-2" unarmeddefense="-2" playerrace="yes" walk="yes" giveperson="yes"
giveunit="yes" getitem="yes" recruitethereal="yes" equipment="yes">
<ai splitsize="10000" moverandom="yes"/>
<ai splitsize="10000" moverandom="yes" learn="yes"/>
<skill name="alchemy" modifier="2"/>
<skill name="trade" modifier="-3"/>
<skill name="forestry" modifier="1"/>
@ -870,7 +870,7 @@ giveunit="yes" getitem="yes" recruitethereal="yes" equipment="yes">
<familiar race="imp"/>
</race>
<race name="troll" magres="10" maxaura="1" regaura="1" recruitcost="90" maintenance="10" weight="2000" capacity="1080" speed="1" hp="30" ac="1" damage="1d5+3" unarmedattack="-2" unarmeddefense="-2" playerrace="yes" walk="yes" giveperson="yes" giveunit="yes" getitem="yes" equipment="yes">
<ai splitsize="10000" moverandom="yes"/>
<ai splitsize="10000" moverandom="yes" learn="yes"/>
<skill name="mining" modifier="2"/>
<skill name="bow" modifier="-2"/>
<skill name="building" modifier="2"/>
@ -900,7 +900,7 @@ giveunit="yes" getitem="yes" recruitethereal="yes" equipment="yes">
<familiar race="wolf"/>
</race>
<race name="goblin" magres="-5" maxaura="1" regaura="1" recruitcost="40" maintenance="10" weight="600" capacity="440" speed="1" hp="16" damage="1d5" unarmedattack="-2" unarmeddefense="0" playerrace="yes" walk="yes" giveperson="yes" giveunit="yes" getitem="yes" equipment="yes">
<ai splitsize="10000" moverandom="yes"/>
<ai splitsize="10000" moverandom="yes" learn="yes"/>
<skill name="alchemy" modifier="1"/>
<skill name="mining" modifier="1"/>
<skill name="building" modifier="1"/>
@ -957,7 +957,7 @@ giveunit="yes" getitem="yes" recruitethereal="yes" equipment="yes">
<attack type="1" damage="0d0"/>
</race>
<race name="template" maintenance="0" magres="100" maxaura="0" regaura="0" weight="0" capacity="1000" speed="10" hp="10" damage="1d4" unarmedattack="-2" unarmeddefense="-2" playerrace="yes" fly="yes" swim="yes" walk="yes" shapeshift="yes" shapeshiftany="yes" giveperson="yes" giveunit="yes" getitem="yes" recruitethereal="yes" recruitunlimited="yes" equipment="yes">
<ai splitsize="10000" moverandom="yes"/>
<ai splitsize="10000" moverandom="yes" learn="yes"/>
<attack type="1" damage="1d4"/>
</race>
<race name="gnome" magres="100" maxaura="0.0" regaura="0.0" weight="1000" capacity="540" speed="1.0" hp="50" damage="1d4" unarmedattack="10" unarmeddefense="10" attackmodifier="10" defensemodifier="10" walk="yes" teach="no">
@ -1075,7 +1075,7 @@ giveunit="yes" getitem="yes" recruitethereal="yes" equipment="yes">
<attack type="1" damage="1d1"/>
</race>
<race name="seaserpent" magres="50" maxaura="1.0" regaura="1.0" weight="20000" capacity="5000" speed="1.0" hp="600" ac="3" damage="2d15" unarmedattack="0" unarmeddefense="0" attackmodifier="4" defensemodifier="4" swim="yes" teach="no" getitem="yes" resistbash="yes" unarmedguard="yes">
<ai splitsize="6" killpeasants="yes" moverandom="yes" moveattack="yes" scarepeasants="yes"/>
<ai splitsize="6" killpeasants="yes" moverandom="yes" learn="yes" moveattack="yes" scarepeasants="yes"/>
<skill name="tactics" modifier="4"/>
<attack type="4" damage="1d30"/>
<attack type="4" damage="1d30"/>
@ -1086,7 +1086,7 @@ giveunit="yes" getitem="yes" recruitethereal="yes" equipment="yes">
<race name="snotling" magres="-5" maxaura="1" regaura="1"
maintenance="10" weight="1000" capacity="540" speed="1" hp="24" damage="1d5" unarmedattack="-2" unarmeddefense="-2" playerrace="no" walk="yes" giveperson="yes" giveunit="yes" getitem="yes" equipment="yes">
<ai splitsize="10000" moverandom="yes"/>
<ai splitsize="10000" moverandom="yes" learn="yes"/>
<skill name="alchemy" modifier="1"/>
<skill name="mining" modifier="1"/>
<skill name="building" modifier="1"/>
@ -1115,7 +1115,7 @@ giveunit="yes" getitem="yes" recruitethereal="yes" equipment="yes">
<familiar race="demon"/>
</race>
<race name="elf" magres="10" maxaura="1" regaura="1.25" recruitcost="130" maintenance="10" weight="1000" capacity="540" speed="1" hp="18" damage="1d5" unarmedattack="-2" unarmeddefense="-2" playerrace="yes" walk="yes" giveperson="yes" giveunit="yes" getitem="yes" equipment="yes">
<ai splitsize="10000" moverandom="yes"/>
<ai splitsize="10000" moverandom="yes" learn="yes"/>
<skill name="alchemy" modifier="-1"/>
<skill name="mining" modifier="-2"/>
<skill name="bow" modifier="2"/>
@ -1141,7 +1141,7 @@ giveunit="yes" getitem="yes" recruitethereal="yes" equipment="yes">
<familiar race="imp"/>
</race>
<race name="dwarf" magres="5" maxaura="1" regaura="0.5" recruitcost="110" maintenance="10" weight="1000" capacity="540" speed="1" hp="24" damage="1d5" unarmedattack="-2" unarmeddefense="-2" playerrace="yes" walk="yes" giveperson="yes" giveunit="yes" getitem="yes" equipment="yes">
<ai splitsize="10000" moverandom="yes"/>
<ai splitsize="10000" moverandom="yes" learn="yes"/>
<skill name="mining" modifier="2"/>
<skill name="bow" modifier="-1"/>
<skill name="building" modifier="2"/>
@ -1172,7 +1172,7 @@ giveunit="yes" getitem="yes" recruitethereal="yes" equipment="yes">
<familiar race="rat"/>
</race>
<race name="orc" studyspeed="-5" magres="-5" maxaura="1" regaura="1" recruitcost="70" maintenance="10" weight="1000" capacity="540" speed="1" hp="24" damage="1d5" unarmedattack="-2" unarmeddefense="-2" playerrace="yes" walk="yes" giveperson="yes" giveunit="yes" getitem="yes" equipment="yes">
<ai splitsize="10000" moverandom="yes"/>
<ai splitsize="10000" moverandom="yes" learn="yes"/>
<param name="recruit_multi" value="0.5"/>
<skill name="alchemy" modifier="1"/>
<skill name="mining" modifier="1"/>
@ -1202,7 +1202,7 @@ giveunit="yes" getitem="yes" recruitethereal="yes" equipment="yes">
<familiar race="demon"/>
</race>
<race name="shadowdragon" magres="95" maxaura="1.0" regaura="3.0" weight="100" capacity="100000" speed="1.0" hp="2700" ac="10" damage="2d60" unarmedattack="0" unarmeddefense="0" attackmodifier="10" defensemodifier="12" fly="yes" walk="yes" teach="no" getitem="yes" resistbash="yes">
<ai splitsize="1" killpeasants="yes" scarepeasants="yes"/>
<ai splitsize="1" killpeasants="yes" learn="yes" scarepeasants="yes"/>
<skill name="tactics" modifier="20"/>
<skill name="perception" modifier="20"/>
<attack type="4" damage="5d30"/>

View file

@ -590,9 +590,6 @@ msgstr "\"$unit($unit) in $region($region): '$order($command)' - Um in Gletscher
msgid "feedback_unit_not_found"
msgstr "\"$unit($unit) in $region($region): '$order($command)' - Die Einheit wurde nicht gefunden.\""
msgid "feedback_not_inside"
msgstr "\"$unit($unit) in $region($region): '$order($command)' - Die Einheit kontrolliert kein Schiff oder Gebäude.\""
msgid "error206"
msgstr "\"$unit($unit) in $region($region): '$order($command)' - Auf dem Gebäude liegt bereits so ein Zauber.\""
@ -692,6 +689,9 @@ msgstr "\"$unit($unit) in $region($region): '$order($command)' - Die Einheit kan
msgid "error85"
msgstr "\"$unit($unit) in $region($region): '$order($command)' - Es wurde keine Emailadresse angegeben.\""
msgid "error125"
msgstr "\"$unit($unit) in $region($region): '$order($command)' - Es wurde kein Banner angegeben.\""
msgid "starvation"
msgstr "\"$unit($unit) verliert in $region($region) $int($dead) von $int($add($live,$dead)) Personen durch Unterernährung.\""

View file

@ -590,9 +590,6 @@ msgstr "\"$unit($unit) in $region($region): '$order($command)' - You must build
msgid "feedback_unit_not_found"
msgstr "\"$unit($unit) in $region($region): '$order($command)' - The unit could not be found.\""
msgid "feedback_unit_not_found"
msgstr "\"$unit($unit) in $region($region): '$order($command)' - The unit is not the owner of a ship or building.\""
msgid "error206"
msgstr "\"$unit($unit) in $region($region): '$order($command)' - There is alrady a spell on that building.\""
@ -692,6 +689,9 @@ msgstr "\"$unit($unit) in $region($region): '$order($command)' - The unit cannot
msgid "error85"
msgstr "\"$unit($unit) in $region($region): '$order($command)' - No email address was supplied.\""
msgid "error125"
msgstr "\"$unit($unit) in $region($region): '$order($command)' - No banner text was supplied.\""
msgid "starvation"
msgstr "\"$unit($unit) loses $int($dead) of $int($add($live,$dead)) people due to starvation in $region($region).\""

View file

@ -2496,10 +2496,6 @@ msgctxt "keyword"
msgid "loot"
msgstr "PLÜNDERE"
msgctxt "keyword"
msgid "expel"
msgstr "VERTREIBE"
msgctxt "calendar"
msgid "month_1"
msgstr "Feldsegen"
@ -6089,7 +6085,7 @@ msgstr "ENDE"
msgctxt "raceinfo"
msgid "tunnelworm"
msgstr "Dieses aus den Tiefen Eresseas stammende gigantische Geschöpf ist dem Leben im Untergrund hervorragend angepasst. Blind, taub und nicht besonders intelligent, aber mit seinen gewaltigen Kräften kann es ganze Berge versetzen oder Wälder roden."
msgstr "Diese aus den Tiefen Eresseas stammende gigantische Geschöpf ist dem Leben im Untergrund hervorragend angepasst. Blind, taub und nicht besonders intelligent, aber mit seinen gewaltigen Kräften kann es ganze Berge versetzen oder Wälder roden."
msgctxt "race"
msgid "aquarian_d"

View file

@ -2167,10 +2167,6 @@ msgctxt "keyword"
msgid "loot"
msgstr "loot"
msgctxt "keyword"
msgid "expel"
msgstr "EXPEL"
msgctxt "keyword"
msgid "guard"
msgstr "GUARD"

View file

@ -18,7 +18,7 @@ end
local function get_target(param)
local ntargets = #targets
if ntargets == 0 then
eressea.log.error("No tunnel targets for [" .. param .. "]")
eressea.log.error("Zero tunnel targets for [" .. param .. "]")
return nil
end
local rn = math.fmod(rng_int(), ntargets)
@ -31,13 +31,10 @@ end
local function tunnel_action(b, param)
local units = tunnel_travelers(b)
eressea.log.info("Tunnel from " .. tostring(b) .. " [" .. param .. "]")
if units then
for _, u in pairs(units) do
local rto = get_target(param)
if not rto then
break
end
eressea.log.info("Tunnel from " .. tostring(b) .. " [" .. param .. "]")
if rto and units then
for _, u in pairs(units) do
u.region = rto
eressea.log.info("teleported " .. tostring(u) .. " to " .. tostring(rto))
end

View file

@ -150,7 +150,6 @@ function process(rules, orders)
callbacks(rules, 'update')
turn_end() -- ageing, etc.
if not config.debug then
write_files(config.locales)
update_scores()
@ -159,7 +158,6 @@ function process(rules, orders)
eressea.log.error("could not write game")
return -1
end
end
return 0
end

View file

@ -3852,6 +3852,10 @@ static void battle_flee(battle * b)
int runhp = (int)(0.9 + unit_max_hp(u) * hpflee(u->status));
if (runhp > 600) runhp = 600;
if (u->ship && fval(u->region->terrain, SEA_REGION)) {
/* keine Flucht von Schiffen auf hoher See */
continue;
}
if (fval(u_race(u), RCF_UNDEAD) || u_race(u) == get_race(RC_SHADOWKNIGHT)) {
/* Untote fliehen nicht. Warum eigentlich? */
continue;
@ -3921,25 +3925,21 @@ void force_leave(region *r, battle *b) {
if (u->building) {
uo = building_owner(u->building);
}
else if (u->ship && r->land) {
if (u->ship && r->land) {
uo = ship_owner(u->ship);
}
else {
continue;
}
if (is_enemy(b, uo, u)) {
if (leave(u, true)) {
message *msg;
if (uo->building) {
msg = msg_message("force_leave_building", "unit owner building", u, uo, uo->building);
if (uo && is_enemy(b, uo, u)) {
message *msg = NULL;
if (u->building) {
msg = msg_message("force_leave_building", "unit owner building", u, uo, u->building);
}
else {
msg = msg_message("force_leave_ship", "unit owner ship", u, uo, uo->ship);
msg = msg_message("force_leave_ship", "unit owner ship", u, uo, u->ship);
}
add_message(&u->faction->msgs, msg);
add_message(&uo->faction->msgs, msg);
msg_release(msg);
if (msg) {
ADDMSG(&u->faction->msgs, msg);
}
leave(u, false);
}
}
}

View file

@ -854,23 +854,6 @@ static void select_regions(state * st, int selectmode)
}
}
}
else if (findmode == 'v') {
region *r;
/* fresh virgin regions */
sprintf(sbuffer, "%svirgin", status);
statusline(st->wnd_status->handle, sbuffer);
for (r = regions; r; r = r->next) {
if (r->age == 0) {
if (selectmode & MODE_SELECT) {
select_coordinate(st->selected, r->x, r->y,
selectmode == MODE_SELECT);
}
else {
highlight_region(r, selectmode == MODE_MARK);
}
}
}
}
else if (findmode == 'c') {
region *r;
sprintf(sbuffer, "%schaos", status);

View file

@ -292,8 +292,15 @@ struct order *ord)
rcfailure = rc_find("toad");
}
if (rcfailure) {
trigger *trestore = trigger_changerace(u, u_race(u), u->irace);
if (trestore) {
int duration = 2 + rng_int() % 8;
change_race(u, duration, rcfailure, NULL);
add_trigger(&u->attribs, "timer", trigger_timeout(duration,
trestore));
u->irace = NULL;
u_setrace(u, rcfailure);
}
}
}
use_pooled(u, itype->rtype, GET_SLACK | GET_RESERVE | GET_POOLED_SLACK,

View file

@ -126,7 +126,7 @@ static void test_get_set_param(CuTest * tc)
{
struct param *par = 0;
test_setup();
CuAssertStrEquals(tc, NULL, get_param(par, "foo"));
CuAssertStrEquals(tc, 0, get_param(par, "foo"));
set_param(&par, "foo", "bar");
set_param(&par, "bar", "foo");
CuAssertStrEquals(tc, "bar", get_param(par, "foo"));

View file

@ -29,10 +29,8 @@ void write_triggers(struct storage *store, const trigger * t)
int read_triggers(struct gamedata *data, trigger ** tp)
{
assert(*tp == NULL);
for (;;) {
trigger_type *ttype;
trigger *tr;
char zText[128];
READ_TOK(data->store, zText, sizeof(zText));
@ -40,30 +38,23 @@ int read_triggers(struct gamedata *data, trigger ** tp)
break;
ttype = tt_find(zText);
assert(ttype || !"unknown trigger-type");
tr = t_new(ttype);
assert(tr->next == NULL);
*tp = t_new(ttype);
if (ttype->read) {
int i = ttype->read(tr, data);
int i = ttype->read(*tp, data);
switch (i) {
case AT_READ_OK:
*tp = tr;
tp = &tr->next;
tp = &(*tp)->next;
break;
case AT_READ_FAIL:
t_free(tr);
free(tr);
t_free(*tp);
free(*tp);
*tp = NULL;
break;
default:
t_free(tr);
free(tr);
assert(!"invalid return value");
break;
}
}
else {
*tp = tr;
tp = &tr->next;
}
}
return 0;
}
@ -71,12 +62,10 @@ int read_triggers(struct gamedata *data, trigger ** tp)
trigger *t_new(trigger_type * ttype)
{
trigger *t = calloc(1, sizeof(trigger));
if (t) {
if (!t) abort();
t->type = ttype;
if (ttype->initialize) {
if (ttype->initialize)
ttype->initialize(t);
}
}
return t;
}

View file

@ -538,13 +538,8 @@ const char *faction_getbanner(const faction * f)
void faction_setbanner(faction * f, const char *banner)
{
if (banner && banner[0]) {
f->banner_id = dbstring_save(banner);
}
else {
f->banner_id = 0;
}
}
const char *faction_getpassword(const faction *f) {
if (f->password_id > 0) {
@ -664,7 +659,7 @@ void remove_empty_factions(void)
for (fp = &factions; *fp;) {
faction *f = *fp;
if (!(f->_alive && f->units!=NULL) && !fval(f, FFL_PAUSED|FFL_NOIDLEOUT)) {
if (!(f->_alive && f->units!=NULL) && !fval(f, FFL_NOIDLEOUT)) {
destroyfaction(fp);
}
else {

View file

@ -406,10 +406,6 @@ item *i_add(item ** pi, item * i)
void i_merge(item ** pi, item ** si)
{
if (*pi == NULL) {
*pi = *si;
}
else {
item *i = *si;
while (i) {
item *itmp;
@ -431,7 +427,6 @@ void i_merge(item ** pi, item ** si)
i = itmp;
}
}
}
*si = NULL;
}

View file

@ -65,43 +65,6 @@ static void test_uchange(CuTest * tc, unit * u, const resource_type * rtype) {
test_log_stop(log, sl);
}
void test_merge_items(CuTest *tc)
{
item *src = NULL, *dst = NULL;
const struct item_type *itype, *ihorse;
test_setup();
itype = test_create_itemtype("iron");
ihorse = test_create_itemtype("horse");
i_merge(&dst, &src);
CuAssertPtrEquals(tc, NULL, dst);
CuAssertPtrEquals(tc, NULL, src);
i_change(&src, itype, 1);
CuAssertIntEquals(tc, 1, i_get(src, itype));
i_merge(&dst, &src);
CuAssertPtrEquals(tc, NULL, src);
CuAssertIntEquals(tc, 1, i_get(dst, itype));
i_change(&src, itype, 1);
CuAssertIntEquals(tc, 1, i_get(src, itype));
i_merge(&dst, &src);
CuAssertPtrEquals(tc, NULL, src);
CuAssertIntEquals(tc, 2, i_get(dst, itype));
i_change(&src, itype, 1);
i_change(&src, ihorse, 1);
CuAssertIntEquals(tc, 1, i_get(src, itype));
CuAssertIntEquals(tc, 1, i_get(src, ihorse));
i_merge(&dst, &src);
CuAssertPtrEquals(tc, NULL, src);
CuAssertIntEquals(tc, 3, i_get(dst, itype));
CuAssertIntEquals(tc, 1, i_get(dst, ihorse));
test_teardown();
}
void test_change_item(CuTest * tc)
{
unit * u;
@ -234,7 +197,6 @@ 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_merge_items);
SUITE_ADD_TEST(suite, test_change_item);
SUITE_ADD_TEST(suite, test_get_resource);
SUITE_ADD_TEST(suite, test_resource_type);

View file

@ -294,6 +294,7 @@ void free_messagelist(mlist *msgs)
message *add_message(message_list ** pm, message * m)
{
assert(m && m->type);
if (m != NULL) {
struct mlist *mnew = malloc(sizeof(struct mlist));
if (!mnew) abort();

View file

@ -220,16 +220,16 @@ static void test_getstrtoken(CuTest *tc) {
CuAssertStrEquals(tc, "durr", getstrtoken());
CuAssertStrEquals(tc, "", getstrtoken());
CuAssertStrEquals(tc, "", getstrtoken());
CuAssertStrEquals(tc, NULL, getstrtoken());
CuAssertStrEquals(tc, 0, getstrtoken());
init_tokens_str(0);
CuAssertStrEquals(tc, NULL, getstrtoken());
CuAssertStrEquals(tc, 0, getstrtoken());
}
static void test_skip_token(CuTest *tc) {
init_tokens_str("hurr \"durr\"");
skip_token();
CuAssertStrEquals(tc, "durr", getstrtoken());
CuAssertStrEquals(tc, NULL, getstrtoken());
CuAssertStrEquals(tc, 0, getstrtoken());
}
static void test_replace_order(CuTest *tc) {

View file

@ -218,7 +218,7 @@ extern "C" {
#define RCF_ATTACK_MOVED (1<<27) /* may attack if it has moved */
#define RCF_MIGRANTS (1<<28) /* may have migrant units (human bonus) */
#define RCF_DEFAULT (RCF_CANSAIL|RCF_AI_LEARN)
#define RCF_DEFAULT RCF_CANSAIL
/* Economic flags */
#define ECF_GIVEPERSON (1<<0) /* Uebergibt Personen */

View file

@ -82,6 +82,9 @@
#define MAXORDERS 256
#define MAXPERSISTENT 128
/* exported symbols symbols */
int g_writegame = 1;
static void read_alliances(gamedata *data)
{
storage *store = data->store;
@ -1770,6 +1773,9 @@ int writegame(const char *filename)
stream strm;
FILE *F;
if (g_writegame == 0) {
return -1;
}
create_directories();
path_join(datapath(), filename, path, sizeof(path));
/* make sure we don't overwrite an existing file (hard links) */

View file

@ -23,6 +23,8 @@ extern "C" {
* dass hier ein Fehler (fehlende ") vorliegt */
/* TODO: is this *really* still in use? */
extern int g_writegame;
int readgame(const char *filename);
int writegame(const char *filename);

View file

@ -1218,11 +1218,9 @@ int invisible(const unit * target, const unit * viewer)
if (hidden > target->number) hidden = target->number;
if (viewer) {
const resource_type *rtype = get_resourcetype(R_AMULET_OF_TRUE_SEEING);
if (rtype) {
hidden -= i_get(viewer->items, rtype->itype);
}
}
}
return hidden;
}
}

View file

@ -8,7 +8,7 @@
#ifndef ERESSEA_VERSION
/* the version number, if it was not passed to make with -D */
#define ERESSEA_VERSION "3.30.0"
#define ERESSEA_VERSION "3.28.0"
#endif
const char *eressea_version(void) {

View file

@ -326,7 +326,7 @@ static double peasant_luck_factor(void)
return config_get_flt("rules.peasants.peasantluck.factor", PEASANTLUCK);
}
#define ROUND_BIRTHS(growth) (int)ceil(growth)
#define ROUND_BIRTHS(growth) ((int)growth)
int peasant_luck_effect(int peasants, int luck, int maxp, double variance)
{
@ -1335,7 +1335,7 @@ static void remove_idle_players(void)
for (fp = &factions; *fp;) {
faction *f = *fp;
if (!is_monsters(f)) {
if (RemoveNMRNewbie() && !fval(f, FFL_PAUSED|FFL_NOIDLEOUT)) {
if (RemoveNMRNewbie() && !fval(f, FFL_NOIDLEOUT)) {
if (f->age >= 0 && f->age < MAXNEWPLAYERS) {
++newbies[f->age];
}
@ -2162,8 +2162,13 @@ int banner_cmd(unit * u, struct order *ord)
init_order(ord, NULL);
s = getstrtoken();
if (!s || !s[0]) {
cmistake(u, ord, 125, MSG_EVENT);
}
else {
faction_setbanner(u->faction, s);
ADDMSG(&u->faction->msgs, msg_message("changebanner", "value", s));
}
return 0;
}
@ -3934,12 +3939,11 @@ void init_processor(void)
add_proc_global(p, defaultorders, "Defaults setzen");
}
add_proc_global(p, demographics, "Nahrung, Seuchen, Wachstum, Wanderung");
p += 10;
if (!keyword_disabled(K_SORT)) {
add_proc_region(p, do_sort, "Einheiten sortieren");
p += 10;
add_proc_global(p, restack_units, "Einheiten sortieren");
}
add_proc_order(p, K_EXPEL, expel_cmd, 0, "Einheiten verjagen");
if (!keyword_disabled(K_NUMBER)) {
add_proc_order(p, K_NUMBER, renumber_cmd, 0, "Neue Nummern (Einheiten)");
p += 10;
@ -4016,84 +4020,10 @@ void turn_end(void)
update_spells();
}
typedef enum cansee_t {
CANSEE_DETECTED,
CANSEE_HIDDEN,
CANSEE_INVISIBLE
} cansee_t;
static enum cansee_t cansee_ex(const unit *u, const region *r, const unit *target, int stealth, int rings)
{
enum cansee_t result = CANSEE_HIDDEN;
if (rings >= target->number) {
const resource_type *rtype = get_resourcetype(R_AMULET_OF_TRUE_SEEING);
if (rtype) {
int amulet = i_get(u->items, rtype->itype);
if (amulet <= 0) {
return CANSEE_INVISIBLE;
}
}
else {
return CANSEE_INVISIBLE;
}
}
if (skill_enabled(SK_PERCEPTION)) {
int watch = effskill(u, SK_PERCEPTION, r);
if (stealth > watch) {
return result;
}
}
return CANSEE_DETECTED;
}
static bool is_exposed(const unit *u) {
return u->building || u->ship || is_guard(u) || leftship(u);
}
static bool big_sea_monster(const unit *u, const region *r) {
return ((r->terrain->flags & SEA_REGION) && (u_race(u)->weight >= 5000));
}
bool
cansee_unit(const unit * u, const region *r, const unit * target, int modifier)
/* r kann != u->region sein, wenn es um durchreisen geht */
{
int stealth, rings;
enum cansee_t see;
if (target->number == 0) {
return false;
}
else if (target->faction == u->faction || omniscient(u->faction)) {
return true;
}
else if (is_exposed(target)) {
return true;
}
else if (target->number == 0) {
attrib *a = a_find(target->attribs, &at_creator);
if (a) {
/* u is an empty temporary unit. In this special case we look at the creating unit. */
target = (unit *)a->data.v;
}
else {
return false;
}
}
stealth = eff_stealth(target, r) - modifier;
rings = invisible(target, NULL);
see = cansee_ex(u, r, target, stealth, rings);
if (CANSEE_HIDDEN == see) {
/* bug 2763 and 2754: can see sea serpents on oceans */
return big_sea_monster(u, r);
}
return CANSEE_DETECTED == see;
}
/**
* Determine if unit can be seen by faction.
*
* @param f -- the observing faction
* @param f -- the observiong faction
* @param u -- the unit that is observed
* @param r -- the region that u is obesrved from (see below)
* @param m -- terrain modifier to stealth
@ -4105,16 +4035,12 @@ cansee_unit(const unit * u, const region *r, const unit * target, int modifier)
*/
bool cansee(const faction * f, const region * r, const unit * u, int modifier)
{
unit *u2;
int rings, stealth;
bool bsm, result;
int stealth, rings;
/* quick exits: */
if (u->faction == f || omniscient(f)) {
return true;
}
else if (u->number == 0) {
/* no need to do this in each cansee_unit: */
attrib *a = a_find(u->attribs, &at_creator);
if (a) {
/* u is an empty temporary unit. In this special case we look at the creating unit. */
@ -4124,42 +4050,123 @@ bool cansee(const faction *f, const region *r, const unit *u, int modifier)
return false;
}
}
if (is_exposed(u)) {
/* obviosuly visibile, we only need a viewer in the region */
/* simple visibility, just gotta have a viewer in the region to see 'em */
if (leftship(u) || is_guard(u) || u->building || u->ship) {
return true;
}
rings = invisible(u, NULL);
stealth = eff_stealth(u, r) - modifier;
if (rings < u->number && stealth <= 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, NULL);
if (observation >= stealth) {
return true;
}
}
else {
return true;
}
}
}
}
return (rings <= 0 && stealth <= 0);
}
bool cansee_unit(const unit * u, const unit * target, int modifier)
/* target->region kann != u->region sein, wenn es um durchreisen geht */
{
if (target->number == 0)
return false;
else if (target->faction == u->faction)
return true;
else {
int n, rings;
if (is_guard(target) || target->building
|| target->ship) {
return true;
}
n = eff_stealth(target, target->region) - modifier;
rings = invisible(target, NULL);
if (rings == 0 && n <= 0) {
return true;
}
if (rings && invisible(target, u) >= target->number) {
return false;
}
if (skill_enabled(SK_PERCEPTION)) {
int o = effskill(u, SK_PERCEPTION, target->region);
if (o >= n) {
return true;
}
}
else {
return true;
}
}
return false;
}
bool
cansee_durchgezogen(const faction * f, const region * r, const unit * u,
int modifier)
/* r kann != u->region sein, wenn es um durchreisen geht */
/* und es muss niemand aus f in der region sein, wenn sie vom Turm
* erblickt wird */
{
unit *u2;
if (u->number == 0)
return false;
else if (u->faction == f)
return true;
else {
int rings, n;
if (is_guard(u) || u->building || u->ship) {
return true;
}
n = eff_stealth(u, r) - modifier;
rings = invisible(u, NULL);
if (rings == 0 && n <= 0) {
return true;
}
result = bsm = big_sea_monster(u, r);
for (u2 = r->units; u2; u2 = u2->next) {
if (u2->faction == f) {
enum cansee_t see = cansee_ex(u2, r, u, stealth, rings);
if (see == CANSEE_DETECTED) {
int o;
if (rings && invisible(u, u2) >= u->number)
continue;
o = effskill(u2, SK_PERCEPTION, NULL);
if (o >= n) {
return true;
}
else if (see == CANSEE_HIDDEN && bsm) {
return true;
}
/* still invisible to all: */
result = false;
}
}
return result;
}
return false;
}
bool
seefaction(const faction * f, const region * r, const unit * u, int modifier)
{
if (((f == u->faction) || !fval(u, UFL_ANON_FACTION))
&& cansee(f, r, u, modifier)) {
&& cansee(f, r, u, modifier))
return true;
}
return false;
}
@ -4180,66 +4187,3 @@ int locale_cmd(unit * u, order * ord)
}
return 0;
}
static void expel_building(unit *u, unit *u2, order *ord) {
building *b = u->building;
if (u != building_owner(b)) {
/* error: must be the owner */
cmistake(u, ord, 5, MSG_EVENT);
}
else {
if (leave(u2, true)) {
message *msg = msg_message("force_leave_building", "owner unit building", u, u2, u->building);
add_message(&u->faction->msgs, msg);
add_message(&u2->faction->msgs, msg);
msg_release(msg);
}
}
}
static void expel_ship(unit *u, unit *u2, order *ord) {
ship *sh = u->ship;
if (u != ship_owner(sh)) {
/* error: must be the owner */
cmistake(u, ord, 146, MSG_EVENT);
}
else if (!u->region->land) {
/* error: must not be at sea */
ADDMSG(&u->faction->msgs,
msg_feedback(u, ord, "error_onlandonly", NULL));
}
else {
if (leave(u2, true)) {
message *msg = msg_message("force_leave_ship", "owner unit ship", u, u2, u->ship);
add_message(&u->faction->msgs, msg);
add_message(&u2->faction->msgs, msg);
msg_release(msg);
}
}
}
int expel_cmd(unit *u, order *ord) {
faction *f = u->faction;
unit *u2;
init_order(ord, f->locale);
getunit(u->region, u->faction, &u2);
if (u2 == NULL) {
/* error: target unit not found */
ADDMSG(&u->faction->msgs,
msg_feedback(u, ord, "feedback_unit_not_found", NULL));
return 0;
}
if (u->building) {
expel_building(u, u2, ord);
}
else if (u->ship) {
expel_ship(u, u2, ord);
}
else {
ADDMSG(&u->faction->msgs,
msg_feedback(u, ord, "feedback_not_inside", NULL));
/* error: unit must be owner of a ship or building */
}
return 0;
}

View file

@ -50,7 +50,6 @@ extern "C" {
bool long_order_allowed(const struct unit *u, bool flags_only);
bool password_wellformed(const char *password);
int expel_cmd(struct unit *u, struct order *ord);
int locale_cmd(struct unit *u, struct order *ord);
int password_cmd(struct unit *u, struct order *ord);
int banner_cmd(struct unit *u, struct order *ord);
@ -86,7 +85,9 @@ extern "C" {
bool cansee(const struct faction * f, const struct region * r,
const struct unit *u, int modifier);
bool cansee_unit(const struct unit *u, const struct region *r, const struct unit *who,
bool cansee_durchgezogen(const struct faction *f, const struct region *r,
const struct unit *u, int modifier);
bool cansee_unit(const struct unit *u, const struct unit *target,
int modifier);
bool seefaction(const struct faction *f, const struct region *r,
const struct unit *u, int modifier);

View file

@ -173,95 +173,6 @@ static void test_enter_ship(CuTest * tc)
test_teardown();
}
static void test_expel_building(CuTest *tc) {
unit *u1, *u2;
order *ord;
building *b;
test_setup();
u1 = test_create_unit(test_create_faction(), test_create_plain(0, 0));
u2 = test_create_unit(test_create_faction(), u1->region);
ord = create_order(K_EXPEL, u2->faction->locale, "%s", itoa36(u1->no));
expel_cmd(u2, ord);
CuAssertPtrNotNull(tc, test_find_messagetype(u2->faction->msgs, "feedback_not_inside"));
test_clear_messages(u2->faction);
b = u2->building = u1->building = test_create_building(u1->region, NULL);
CuAssertPtrEquals(tc, u1, building_owner(b));
expel_cmd(u2, ord);
/* Nothing happened: */
CuAssertPtrEquals(tc, u1, building_owner(b));
CuAssertPtrEquals(tc, b, u1->building);
CuAssertPtrEquals(tc, b, u2->building);
CuAssertPtrNotNull(tc, test_find_messagetype(u2->faction->msgs, "error5"));
test_clear_messages(u1->faction);
free_order(ord);
ord = create_order(K_EXPEL, u1->faction->locale, "%s", itoa36(u2->no));
expel_cmd(u1, ord);
/* owner has expelled u2: */
CuAssertPtrEquals(tc, NULL, u2->building);
CuAssertPtrNotNull(tc, test_find_messagetype(u1->faction->msgs, "force_leave_building"));
CuAssertPtrNotNull(tc, test_find_messagetype(u2->faction->msgs, "force_leave_building"));
test_teardown();
}
static void test_expel_ship(CuTest *tc) {
unit *u1, *u2;
order *ord;
ship *sh;
test_setup();
u1 = test_create_unit(test_create_faction(), test_create_plain(0, 0));
u2 = test_create_unit(test_create_faction(), u1->region);
ord = create_order(K_EXPEL, u2->faction->locale, "%s", itoa36(u1->no));
expel_cmd(u2, ord);
CuAssertPtrNotNull(tc, test_find_messagetype(u2->faction->msgs, "feedback_not_inside"));
test_clear_messages(u2->faction);
sh = u2->ship = u1->ship = test_create_ship(u1->region, NULL);
CuAssertPtrEquals(tc, u1, ship_owner(sh));
expel_cmd(u2, ord);
/* Nothing happened: */
CuAssertPtrEquals(tc, u1, ship_owner(sh));
CuAssertPtrEquals(tc, sh, u1->ship);
CuAssertPtrEquals(tc, sh, u2->ship);
CuAssertPtrNotNull(tc, test_find_messagetype(u2->faction->msgs, "error146"));
test_clear_messages(u2->faction);
free_order(ord);
ord = create_order(K_EXPEL, u1->faction->locale, "%s", itoa36(u2->no));
expel_cmd(u1, ord);
/* owner has expelled u2: */
CuAssertPtrEquals(tc, NULL, u2->ship);
CuAssertPtrEquals(tc, sh, leftship(u2));
CuAssertPtrNotNull(tc, test_find_messagetype(u1->faction->msgs, "force_leave_ship"));
CuAssertPtrNotNull(tc, test_find_messagetype(u2->faction->msgs, "force_leave_ship"));
test_teardown();
}
static void test_expel_ship_at_sea(CuTest *tc) {
unit *u1, *u2;
order *ord;
ship *sh;
test_setup();
u1 = test_create_unit(test_create_faction(), test_create_ocean(0, 0));
u2 = test_create_unit(test_create_faction(), u1->region);
sh = u2->ship = u1->ship = test_create_ship(u1->region, NULL);
CuAssertPtrEquals(tc, u1, ship_owner(sh));
ord = create_order(K_EXPEL, u1->faction->locale, "%s", itoa36(u2->no));
expel_cmd(u1, ord);
/* owner has not expelled u2: */
CuAssertPtrNotNull(tc, test_find_messagetype(u1->faction->msgs, "error_onlandonly"));
CuAssertPtrEquals(tc, sh, u2->ship);
test_teardown();
}
static void test_display_cmd(CuTest *tc) {
unit *u;
faction *f;
@ -1312,6 +1223,7 @@ static void test_banner_cmd(CuTest *tc) {
order *ord;
test_setup();
mt_create_error(125);
mt_create_va(mt_new("changebanner", NULL), "value:string", MT_NEW_END);
u = test_create_unit(f = test_create_faction(), test_create_region(0, 0, NULL));
@ -1324,8 +1236,8 @@ static void test_banner_cmd(CuTest *tc) {
ord = create_order(K_BANNER, f->locale, NULL);
banner_cmd(u, ord);
CuAssertStrEquals(tc, NULL, faction_getbanner(f));
CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "changebanner"));
CuAssertStrEquals(tc, "Hodor!", faction_getbanner(f));
CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "error125"));
free_order(ord);
test_clear_messages(f);
@ -1897,37 +1809,32 @@ static void test_cansee(CuTest *tc) {
static void test_cansee_ring(CuTest *tc) {
unit *u, *u2;
item_type *iring, *isee;
item_type *itype[2];
test_setup();
u = test_create_unit(test_create_faction(), test_create_region(0, 0, NULL));
u2 = test_create_unit(test_create_faction(), u->region);
scale_number(u2, 2);
iring = test_create_itemtype("roi");
isee = test_create_itemtype("aots");
itype[0] = test_create_itemtype("roi");
itype[1] = test_create_itemtype("aots");
CuAssertPtrNotNull(tc, get_resourcetype(R_RING_OF_INVISIBILITY));
CuAssertPtrEquals(tc, iring->rtype, (void *)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, isee->rtype, (void *)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 hides one person, but not two: */
i_change(&u2->items, iring, 1);
CuAssertTrue(tc, !cansee(u->faction, u->region, u2, 0));
scale_number(u2, 2);
/* 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, iring, 1);
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, isee, 1);
CuAssertTrue(tc, cansee(u->faction, u->region, u2, 0));
/* having more rings than people doesn't help: */
i_change(&u2->items, iring, 1);
i_change(&u->items, itype[1], 1);
CuAssertTrue(tc, cansee(u->faction, u->region, u2, 0));
test_teardown();
@ -1966,42 +1873,6 @@ static void test_cansee_sphere(CuTest *tc) {
test_teardown();
}
/**
* Hidden monsters are seen in oceans if they are big enough.
*/
static void test_cansee_monsters(CuTest *tc) {
unit *u, *u2;
race *rc;
const item_type *itype;
test_setup();
itype = test_create_itemtype("roi");
u = test_create_unit(test_create_faction(), test_create_ocean(0, 0));
u2 = test_create_unit(test_create_faction(), u->region);
rc = test_create_race("seaserpent");
rc->weight = 4999;
u_setrace(u2, rc);
CuAssertTrue(tc, cansee(u->faction, u->region, u2, 0));
CuAssertTrue(tc, cansee(u->faction, u->region, u2, 2));
set_level(u2, SK_STEALTH, 1);
CuAssertTrue(tc, !cansee(u->faction, u->region, u2, 0));
CuAssertTrue(tc, cansee(u->faction, u->region, u2, 1));
rc->weight = 5000;
/* no stealth for fatties at sea */
CuAssertTrue(tc, cansee(u->faction, u->region, u2, 0));
CuAssertTrue(tc, cansee(u->faction, u->region, u2, 1));
/* rings still work */
i_change(&u2->items, itype, 1);
CuAssertTrue(tc, !cansee(u->faction, u->region, u2, 0));
CuAssertTrue(tc, !cansee(u->faction, u->region, u2, 2));
test_teardown();
}
static void test_nmr_timeout(CuTest *tc) {
test_setup();
CuAssertIntEquals(tc, 0, NMRTimeout());
@ -2449,9 +2320,6 @@ CuSuite *get_laws_suite(void)
SUITE_ADD_TEST(suite, test_enter_building);
SUITE_ADD_TEST(suite, test_enter_ship);
SUITE_ADD_TEST(suite, test_display_cmd);
SUITE_ADD_TEST(suite, test_expel_building);
SUITE_ADD_TEST(suite, test_expel_ship);
SUITE_ADD_TEST(suite, test_expel_ship_at_sea);
SUITE_ADD_TEST(suite, test_rule_force_leave);
SUITE_ADD_TEST(suite, test_force_leave_buildings);
SUITE_ADD_TEST(suite, test_force_leave_ships);
@ -2474,7 +2342,6 @@ CuSuite *get_laws_suite(void)
SUITE_ADD_TEST(suite, test_cansee);
SUITE_ADD_TEST(suite, test_cansee_ring);
SUITE_ADD_TEST(suite, test_cansee_sphere);
SUITE_ADD_TEST(suite, test_cansee_monsters);
SUITE_ADD_TEST(suite, test_nmr_timeout);
SUITE_ADD_TEST(suite, test_long_orders);
SUITE_ADD_TEST(suite, test_long_order_on_ocean);

View file

@ -1273,12 +1273,10 @@ static void do_fumble(castorder * co)
unit *caster = co_get_caster(co);
const spell *sp = co->sp;
int level = co->level;
int duration;
double effect;
static int rc_cache;
static const race *rc_toad = NULL;
fumble_f fun;
trigger *trestore;
int duration;
ADDMSG(&caster->faction->msgs,
msg_message("patzer", "unit region spell", caster, r, sp));
@ -1295,26 +1293,32 @@ static void do_fumble(castorder * co)
break;
case 1: /* toad */
/* one or two things will happen: the toad changes its race back,
{
/* one or two things will happen: the toad changes her race back,
* and may or may not get toadslime.
* The list of things to happen are attached to a timeout
* trigger and that's added to the triggerlist of the mage gone toad.
* trigger and that's added to the triggerlit of the mage gone toad.
*/
if (rc_changed(&rc_cache)) {
rc_toad = get_race(RC_TOAD);
}
duration = rng_int() % level / 2;
trestore = change_race(mage, duration, rc_toad, NULL);
if (trestore) {
static const race *rc_toad;
trigger *trestore = trigger_changerace(mage, u_race(mage), mage->irace);
if (chance(0.7)) {
const resource_type *rtype = rt_find("toadslime");
if (rtype) {
t_add(&trestore, trigger_giveitem(mage, rtype->itype, 1));
}
}
ADDMSG(&r->msgs, msg_message("patzer6", "unit region spell", mage, r, sp));
duration = rng_int() % level / 2;
if (duration < 2) duration = 2;
add_trigger(&mage->attribs, "timer", trigger_timeout(duration, trestore));
if (rc_changed(&rc_cache)) {
rc_toad = get_race(RC_TOAD);
}
u_setrace(mage, rc_toad);
mage->irace = NULL;
ADDMSG(&r->msgs, msg_message("patzer6", "unit region spell", mage, r, sp));
break;
}
/* fall-through is intentional! */
case 2:
/* temporary skill loss */
@ -1326,7 +1330,6 @@ static void do_fumble(castorder * co)
c->data.i = SK_MAGIC;
ADDMSG(&caster->faction->msgs, msg_message("patzer2", "unit region", caster, r));
break;
case 3:
case 4:
/* Spruch schlaegt fehl, alle Magiepunkte weg */
@ -2578,7 +2581,7 @@ static castorder *cast_cmd(unit * u, order * ord)
skill = limit;
}
sp = unit_getspell(mage, s, mage->faction->locale);
if (sp == NULL || sp->sptyp & NOTFAMILIARCAST) {
if (sp->sptyp & NOTFAMILIARCAST) {
/* Fehler: "Diesen Spruch kann der Vertraute nicht zaubern" */
cmistake(u, ord, 177, MSG_MAGIC);
return 0;

View file

@ -200,7 +200,7 @@ static int parse_args(int argc, char **argv)
const char *arg;
switch (argi[1]) {
case 'D':
config_set("config.debug", "1");
g_writegame = 0;
break;
case 'c':
i = get_arg(argc, argv, 2, i, &arg, 0);

View file

@ -258,7 +258,7 @@ get_island_info(region * root, int *size_p, int *inhabited_p, int *maxage_p)
if (r->units) {
unit *u;
for (u = r->units; u; u = u->next) {
if (!fval(u->faction, FFL_PAUSED | FFL_NOIDLEOUT) && u->faction->age > maxage) {
if (!fval(u->faction, FFL_NOIDLEOUT) && u->faction->age > maxage) {
maxage = u->faction->age;
}
}

View file

@ -763,17 +763,12 @@ void monster_cannibalism(unit *u)
for (u2 = u->next; u2; u2 = u2->next) {
if (u2->_race == u->_race) {
i_merge(&u->items, &u2->items);
stats_count("monsters.cannibalism", u2->number);
u2->number = 0;
}
}
}
static bool monster_can_learn(const race *rc) {
return (rc->flags & (RCF_NOLEARN|RCF_AI_LEARN)) == RCF_AI_LEARN;
}
void plan_monsters(faction * f)
{
region *r;
@ -874,7 +869,7 @@ void plan_monsters(faction * f)
long_order = create_order(K_PIRACY, f->locale, NULL);
}
else {
if (monster_can_learn(rc)) {
if (rc->flags & RCF_AI_LEARN) {
long_order = monster_learn(u);
}
}

View file

@ -95,18 +95,15 @@ static void handle_unit(void *userData, int no) {
static void handle_order(void *userData, const char *str) {
parser_state *state = (parser_state *)userData;
const char * tok, *input;
const char * tok, *input = str;
char buffer[64];
const struct locale *lang;
param_t p;
faction * f = state->f;
lang = f ? f->locale : default_locale;
ltrim(&str);
if (*str == 0) return;
input = str;
tok = parse_token(&input, buffer, sizeof(buffer));
if (tok) {
param_t p = findparam(tok, lang);
p = findparam(tok, lang);
if (p == P_FACTION || p == P_GAMENAME) {
tok = parse_token(&input, buffer, sizeof(buffer));
if (tok) {
@ -146,7 +143,6 @@ static void handle_order(void *userData, const char *str) {
}
}
}
}
int parseorders(FILE *F)
{

View file

@ -2203,10 +2203,6 @@ report_plaintext(const char *filename, report_context * ctx,
}
}
}
else while (u && u->building) {
/* do not report units in buildings */
u = u->next;
}
while (u && !u->ship) {
if (visible_unit(u, f, stealthmod, r->seen.mode)) {
nr_unit(out, f, u, 4, r->seen.mode);

View file

@ -1045,7 +1045,7 @@ static void cb_add_address(region *r, unit *ut, void *cbdata) {
for (u = r->units; u; u = u->next) {
faction *sf = visible_faction(f, u);
assert(u->faction != f); /* if this is see_travel only, then I shouldn't be here. */
if (data->lastf != sf && cansee_unit(ut, r, u, data->stealthmod)) {
if (data->lastf != sf && cansee_unit(ut, u, data->stealthmod)) {
add_seen_faction_i(data->flist, sf);
data->lastf = sf;
}
@ -2361,7 +2361,7 @@ static void count_cb(region *r, unit *u, void *cbdata) {
count_data *data = (count_data *)cbdata;
const struct faction *f = data->f;
if (r != u->region && (!u->ship || ship_owner(u->ship) == u)) {
if (cansee(f, r, u, 0)) {
if (cansee_durchgezogen(f, r, u, 0)) {
++data->n;
}
}
@ -2379,9 +2379,16 @@ bool visible_unit(const unit *u, const faction *f, int stealthmod, seen_mode mod
if (u->faction == f) {
return true;
}
else if (mode >= seen_lighthouse && stealthmod > INT_MIN) {
else if (mode >= seen_lighthouse) {
if (stealthmod > INT_MIN) {
if ((u->region->terrain->flags & SEA_REGION) && (u_race(u)->weight >= 5000)) {
return true;
}
if (mode >= seen_travel || u->building || u->ship || is_guard(u)) {
return cansee(f, u->region, u, stealthmod);
}
}
}
return false;
}

View file

@ -13,7 +13,7 @@
#include "util/param.h"
#include "util/parser.h"
static void sort_before(unit *v, unit **up) {
void sort_before(unit *v, unit **up) {
unit *u = *up;
region *r = u->region;
unit **vp = &r->units;
@ -24,8 +24,10 @@ static void sort_before(unit *v, unit **up) {
u->next = v;
}
void do_sort(region *r)
void restack_units(void)
{
region *r;
for (r = regions; r; r = r->next) {
unit **up = &r->units;
bool sorted = false;
while (*up) {
@ -119,12 +121,5 @@ void do_sort(region *r)
}
}
}
void restack_units(void)
{
region *r;
for (r = regions; r; r = r->next) {
do_sort(r);
}
}

View file

@ -1,6 +1,3 @@
#pragma once
struct region;
void restack_units(void);
void do_sort(struct region *r);

View file

@ -500,10 +500,7 @@ static const race *select_familiar(const race * magerace, int level, magic_t mag
return rcfixed;
}
if (magerace->familiars[0] == NULL) {
log_error("a %s magician is trying to summon a familiar", magerace->_name);
return NULL;
}
assert(magerace->familiars[0]);
if (rnd >= 100 - (level * 5)) {
retval = magerace->familiars[magiegebiet];
assert(retval);
@ -571,7 +568,7 @@ static int sp_summon_familiar(castorder * co)
}
rc = select_familiar(caster->_race, cast_level, caster->faction->magiegebiet);
if (rc == NULL) {
log_error("could not find suitable familiar for %s.\n", unitname(caster));
log_error("could not find suitable familiar for %s.\n", caster->faction->race->_name);
return 0;
}
@ -4554,13 +4551,13 @@ int sp_illusionary_shapeshift(castorder * co)
return 0;
}
if (NULL == change_race(u, 3 + (int)power, NULL, rc)) {
ADDMSG(&mage->faction->msgs, msg_feedback(mage, co->order,
"sp_shapeshift_fail", "target race", u, rc));
return 0;
}
add_trigger(&u->attribs, "timer", trigger_timeout((int)power + 3,
trigger_changerace(u, NULL, irace)));
u->irace = rc;
ADDMSG(&mage->faction->msgs, msg_message("shapeshift_effect",
"mage target race", mage, u, rc));
return cast_level;
}

View file

@ -5,7 +5,6 @@
#include <kernel/config.h>
#include <kernel/curse.h>
#include <kernel/event.h>
#include <kernel/faction.h>
#include <kernel/order.h>
#include <kernel/plane.h>
@ -20,9 +19,6 @@
#include <attributes/attributes.h>
#include <triggers/changerace.h>
#include <triggers/timeout.h>
#include <CuTest.h>
#include <tests.h>
@ -284,58 +280,6 @@ static void test_watch_region(CuTest *tc) {
test_teardown();
}
static void test_change_race(CuTest *tc) {
unit *u;
race *rctoad, *rcsmurf;
trigger **tp, *tr;
timeout_data *td;
changerace_data *crd;
test_setup();
rctoad = test_create_race("toad");
rcsmurf = test_create_race("smurf");
u = test_create_unit(test_create_faction(), test_create_plain(0, 0));
CuAssertPtrEquals(tc, (void *)u->faction->race, (void *)u->_race);
CuAssertPtrNotNull(tc, tr = change_race(u, 2, rctoad, NULL));
CuAssertPtrEquals(tc, (void *)rctoad, (void *)u->_race);
CuAssertPtrEquals(tc, NULL, (void *)u->irace);
CuAssertPtrEquals(tc, &tt_timeout, tr->type);
CuAssertPtrNotNull(tc, u->attribs);
CuAssertPtrEquals(tc, NULL, u->attribs->next);
tp = get_triggers(u->attribs, "timer");
CuAssertPtrNotNull(tc, tp);
CuAssertPtrEquals(tc, tr, *tp);
CuAssertPtrEquals(tc, NULL, tr->next);
td = (timeout_data *)tr->data.v;
CuAssertPtrNotNull(tc, td);
CuAssertIntEquals(tc, 2, td->timer);
CuAssertPtrNotNull(tc, td->triggers);
CuAssertPtrEquals(tc, &tt_changerace, td->triggers->type);
CuAssertPtrEquals(tc, NULL, td->triggers->next);
crd = (changerace_data *)td->triggers->data.v;
CuAssertPtrEquals(tc, (void *)u->faction->race, (void *)crd->race);
CuAssertPtrEquals(tc, NULL, (void *)crd->irace);
/* change race, but do not add a second change_race trigger */
CuAssertPtrEquals(tc, tr, change_race(u, 2, rcsmurf, NULL));
CuAssertPtrNotNull(tc, u->attribs);
CuAssertPtrEquals(tc, NULL, u->attribs->next);
CuAssertPtrEquals(tc, NULL, tr->next);
CuAssertPtrEquals(tc, (void *)rcsmurf, (void *)u->_race);
CuAssertPtrEquals(tc, NULL, (void *)u->irace);
td = (timeout_data *)tr->data.v;
CuAssertPtrNotNull(tc, td);
CuAssertIntEquals(tc, 2, td->timer);
CuAssertPtrNotNull(tc, td->triggers);
CuAssertPtrEquals(tc, &tt_changerace, td->triggers->type);
CuAssertPtrEquals(tc, NULL, td->triggers->next);
crd = (changerace_data *)td->triggers->data.v;
CuAssertPtrEquals(tc, (void *)u->faction->race, (void *)crd->race);
CuAssertPtrEquals(tc, NULL, (void *)crd->irace);
test_teardown();
}
CuSuite *get_spells_suite(void)
{
CuSuite *suite = CuSuiteNew();
@ -345,6 +289,5 @@ CuSuite *get_spells_suite(void)
SUITE_ADD_TEST(suite, test_good_dreams);
SUITE_ADD_TEST(suite, test_bad_dreams);
SUITE_ADD_TEST(suite, test_dreams);
SUITE_ADD_TEST(suite, test_change_race);
return suite;
}

View file

@ -1184,7 +1184,7 @@ int sp_appeasement(struct castorder * co)
/* Fliehende Einheiten verlassen auf jeden Fall Gebaeude und Schiffe. */
if (!(r->terrain->flags & SEA_REGION)) {
(void)leave(mage, false);
leave(mage, false);
}
/* und bewachen nicht */
setguard(mage, false);

View file

@ -119,7 +119,7 @@ int spy_cmd(unit * u, struct order *ord)
if (!target) {
ADDMSG(&u->faction->msgs,
msg_feedback(u, u->thisorder, "feedback_unit_not_found", NULL));
msg_feedback(u, u->thisorder, "feedback_unit_not_found", ""));
return 0;
}
if (effskill(u, SK_SPY, NULL) < 1) {

View file

@ -74,7 +74,7 @@ void travelthru_add(region * r, unit * u)
bool travelthru_cansee(const struct region *r, const struct faction *f, const struct unit *u) {
if (r != u->region && (!u->ship || ship_owner(u->ship) == u)) {
return cansee(f, r, u, 0);
return cansee_durchgezogen(f, r, u, 0);
}
return false;
}

View file

@ -86,10 +86,8 @@ trigger_type tt_changefaction = {
trigger *trigger_changefaction(unit * u, struct faction * f)
{
trigger *t = t_new(&tt_changefaction);
if (t) {
changefaction_data *td = (changefaction_data *)t->data.v;
td->unit = u;
td->faction = f;
}
return t;
}

View file

@ -1,6 +1,5 @@
#include <platform.h>
#include "changerace.h"
#include "timeout.h"
/* kernel includes */
#include <kernel/unit.h>
@ -27,6 +26,12 @@
** restore a mage that was turned into a toad
**/
typedef struct changerace_data {
struct unit *u;
const struct race *race;
const struct race *irace;
} changerace_data;
static void changerace_init(trigger * t)
{
t->data.v = calloc(1, sizeof(changerace_data));
@ -85,35 +90,10 @@ trigger_type tt_changerace = {
trigger *trigger_changerace(unit * u, const race * prace, const race * irace)
{
trigger *t = t_new(&tt_changerace);
if (t) {
changerace_data *td = (changerace_data *)t->data.v;
td->u = u;
td->race = prace;
td->irace = irace;
}
return t;
}
extern struct trigger *change_race(struct unit *u, int duration, const struct race *urace, const struct race *irace) {
trigger **texists = get_triggers(u->attribs, "timer");
trigger *tr = NULL;
if (texists) {
tr = *texists;
}
else {
trigger *trestore = trigger_changerace(u, u_race(u), u->irace);
if (trestore) {
tr = trigger_timeout(duration, trestore);
add_trigger(&u->attribs, "timer", tr);
}
}
if (tr) {
u->irace = irace;
if (urace) {
u_setrace(u, urace);
}
}
return tr;
}

View file

@ -10,15 +10,11 @@ extern "C" {
struct unit;
struct race;
typedef struct changerace_data {
struct unit *u;
const struct race *race;
const struct race *irace;
} changerace_data;
extern struct trigger_type tt_changerace;
extern struct trigger *change_race(struct unit *u, int duration, const struct race *urace, const struct race *irace);
extern struct trigger *trigger_changerace(struct unit *u,
const struct race *urace, const struct race *irace);
#ifdef __cplusplus
}
#endif

View file

@ -71,8 +71,6 @@ trigger_type tt_clonedied = {
trigger *trigger_clonedied(unit * u)
{
trigger *t = t_new(&tt_clonedied);
if (t) {
t->data.v = (void *)u;
}
return t;
}

View file

@ -115,7 +115,6 @@ trigger *trigger_createcurse(struct unit * mage, struct unit * target,
const curse_type * ct, double vigour, int duration, double effect, int men)
{
trigger *t = t_new(&tt_createcurse);
if (t) {
createcurse_data *td = (createcurse_data *)t->data.v;
td->mage = mage;
td->target = target;
@ -124,6 +123,5 @@ trigger *trigger_createcurse(struct unit * mage, struct unit * target,
td->duration = duration;
td->effect = effect;
td->men = men;
}
return t;
}

View file

@ -103,12 +103,10 @@ trigger *trigger_createunit(region * r, struct faction * f,
const struct race * rc, int number)
{
trigger *t = t_new(&tt_createunit);
if (t) {
createunit_data *td = (createunit_data *)t->data.v;
td->r = r;
td->f = f;
td->race = rc;
td->number = number;
}
return t;
}

View file

@ -96,11 +96,9 @@ trigger_type tt_giveitem = {
trigger *trigger_giveitem(unit * u, const item_type * itype, int number)
{
trigger *t = t_new(&tt_giveitem);
if (t) {
giveitem_data *td = (giveitem_data *)t->data.v;
td->number = number;
td->u = u;
td->itype = itype;
}
return t;
}

View file

@ -61,8 +61,6 @@ trigger_type tt_killunit = {
trigger *trigger_killunit(unit * u)
{
trigger *t = t_new(&tt_killunit);
if (t) {
t->data.v = (void *)u;
}
return t;
}

View file

@ -130,8 +130,6 @@ trigger_type tt_shock = {
trigger *trigger_shock(unit * u)
{
trigger *t = t_new(&tt_shock);
if (t) {
t->data.v = (void *)u;
}
return t;
}

View file

@ -16,6 +16,12 @@
** timeout
**/
typedef struct timeout_data {
trigger *triggers;
int timer;
variant trigger_data;
} timeout_data;
static void timeout_init(trigger * t)
{
t->data.v = calloc(1, sizeof(timeout_data));
@ -79,10 +85,8 @@ trigger_type tt_timeout = {
trigger *trigger_timeout(int time, trigger * callbacks)
{
trigger *t = t_new(&tt_timeout);
if (t) {
timeout_data *td = (timeout_data *)t->data.v;
td->triggers = callbacks;
td->timer = time;
}
return t;
}

View file

@ -7,11 +7,6 @@ extern "C" {
struct trigger_type;
struct trigger;
typedef struct timeout_data {
struct trigger *triggers;
int timer;
} timeout_data;
extern struct trigger_type tt_timeout;
extern struct trigger *trigger_timeout(int time, struct trigger *callbacks);

View file

@ -156,8 +156,7 @@ const char *keywords[MAXKEYWORDS] = {
"promote",
"pay",
"loot",
"expel",
"autostudy",
"locale"
"locale",
};

View file

@ -71,7 +71,6 @@ extern "C"
K_PROMOTION,
K_PAY,
K_LOOT,
K_EXPEL,
K_AUTOSTUDY,
K_LOCALE,
MAXKEYWORDS,

View file

@ -24,9 +24,7 @@ typedef struct parse_state {
static parse_state *states;
#define TRIMMED(wc) (iswspace(wc) || iswcntrl(wc) || (wc) == 160 || (wc) == 8199 || (wc) == 8239)
int ltrim(const char **str_p)
static int eatwhitespace_c(const char **str_p)
{
int ret = 0;
wint_t wc;
@ -34,10 +32,11 @@ int ltrim(const char **str_p)
const char *str = *str_p;
/* skip over potential whitespace */
while (*str) {
wc = *(unsigned char *)str;
if (~wc & 0x80) {
if (!TRIMMED(wc)) break;
for (;;) {
unsigned char utf8_character = (unsigned char)*str;
if (~utf8_character & 0x80) {
if (!iswspace(utf8_character))
break;
++str;
}
else {
@ -46,7 +45,8 @@ int ltrim(const char **str_p)
log_warning("illegal character sequence in UTF8 string: %s\n", str);
break;
}
if (!TRIMMED(wc)) break;
if (!iswspace(wc))
break;
str += len;
}
}
@ -94,7 +94,7 @@ void parser_popstate(void)
bool parser_end(void)
{
if (states->current_token) {
ltrim(&states->current_token);
eatwhitespace_c(&states->current_token);
return *states->current_token == 0;
}
return true;
@ -103,7 +103,7 @@ bool parser_end(void)
void skip_token(void)
{
char quotechar = 0;
ltrim(&states->current_token);
eatwhitespace_c(&states->current_token);
while (*states->current_token) {
wint_t wc;
@ -152,7 +152,7 @@ char *parse_token(const char **str, char *lbuf, size_t buflen)
if (!ctoken) {
return 0;
}
ltrim(&ctoken);
eatwhitespace_c(&ctoken);
if (!*ctoken) {
if (buflen > 0) {
*cursor = 0;
@ -195,19 +195,18 @@ char *parse_token(const char **str, char *lbuf, size_t buflen)
}
else if (utf8_character == '"' || utf8_character == '\'') {
if (utf8_character == quotechar) {
quotechar = 0;
++ctoken;
break;
}
else if (quotechar == 0 && cstart == ctoken) {
quotechar = utf8_character;
++ctoken;
}
else {
if (cursor - buflen < lbuf - len) {
*cursor++ = *ctoken;
*cursor++ = *ctoken++;
}
}
++ctoken;
}
else if (utf8_character == SPACE_REPLACEMENT) {
if (cursor - buflen < lbuf - len) {

View file

@ -22,7 +22,6 @@ extern "C" {
int getint(void);
int getid(void);
unsigned int atoip(const char *s);
int ltrim(const char **str_p);
#ifdef __cplusplus
}

View file

@ -92,14 +92,8 @@ static void test_parse_token_limit_utf8(CuTest *tc) {
char lbuf[8];
const char *tok;
const char *orig = "a\xc3\xa4\xc3\xb6\xc3\xbc\xc3\x9f"; /* auml ouml uuml szlig, 8 bytes long */
const char *str;
const char *wspace = " \x07\xc2\xa0\t.okay";
const char *str = orig+1;
str = wspace;
tok = parse_token(&str, lbuf, sizeof(lbuf));
CuAssertStrEquals(tc, tok, ".okay");
str = orig + 1;
tok = parse_token(&str, lbuf, sizeof(lbuf));
CuAssertPtrEquals(tc, (void *)(orig + strlen(orig)), (void *)str);
CuAssertStrEquals(tc, tok, "\xc3\xa4\xc3\xb6\xc3\xbc"); /* just three letters fit, 6 bytes long */

View file

@ -21,11 +21,11 @@ static void test_transliterate(CuTest * tc)
CuAssertStrEquals(tc, "aeoeuess", transliterate(buffer, sizeof(buffer), "\xc3\x84\xc3\x96\xc3\x9c\xe1\xba\x9e"));
/* handle buffer that is too small */
CuAssertStrEquals(tc, NULL, transliterate(buffer, 1, "herpderp"));
CuAssertStrEquals(tc, 0, transliterate(buffer, 1, "herpderp"));
CuAssertStrEquals(tc, "", buffer);
CuAssertStrEquals(tc, NULL, transliterate(buffer, 3, "herpderp"));
CuAssertStrEquals(tc, 0, transliterate(buffer, 3, "herpderp"));
CuAssertStrEquals(tc, "he", buffer);
CuAssertStrEquals(tc, NULL, transliterate(buffer, 3, "h\xc3\xa4rpd\xc3\xa4rp"));
CuAssertStrEquals(tc, 0, transliterate(buffer, 3, "h\xc3\xa4rpd\xc3\xa4rp"));
CuAssertStrEquals(tc, "h?", buffer);
}